📄 task.c
字号:
/****************************************************************//* *//* task.c *//* *//* Task Manager for DOS Processes *//* *//* Copyright (c) 1995 *//* Pasquale J. Villani *//* All Rights Reserved *//* *//* This file is part of DOS-C. *//* *//* DOS-C is free software; you can redistribute it and/or *//* modify it under the terms of the GNU General Public License *//* as published by the Free Software Foundation; either version *//* 2, or (at your option) any later version. *//* *//* DOS-C is distributed in the hope that it will be useful, but *//* WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See *//* the GNU General Public License for more details. *//* *//* You should have received a copy of the GNU General Public *//* License along with DOS-C; see the file COPYING. If not, *//* write to the Free Software Foundation, 675 Mass Ave, *//* Cambridge, MA 02139, USA. *//****************************************************************/#include "portab.h"#include "globals.h"#ifdef VERSION_STRINGSstatic BYTE *RcsId = "$Id: task.c,v 1.44 2004/05/10 20:49:37 bartoldeman Exp $";#endif#define toupper(c) ((c) >= 'a' && (c) <= 'z' ? (c) + ('A' - 'a') : (c))#define LOADNGO 0#define LOAD 1#define OVERLAY 3#define LOAD_HIGH 0x80/* static exe_header ExeHeader; to save some bytes, both static and on stack, we recycle SecPathBuffer TE */#define ExeHeader (*(exe_header *)(SecPathName + 0))#define TempExeBlock (*(exec_blk *)(SecPathName + sizeof(exe_header)))#define Shell (SecPathName + sizeof(exe_header) + sizeof(exec_blk))#ifdef __TURBOC__ /* this is a Borlandism and doesn't work elsewhere */ #if sizeof(SecPathName) < sizeof(exe_header) + sizeof(exec_blk) + NAMEMAX #error No room in SecPathName to be recycled! #endif#endif#define CHUNK 32256#define MAXENV 32768u#define ENV_KEEPFREE 83 /* keep unallocated by environment variables */ /* The '65' added to nEnvSize does not cover the additional stuff: + 2 bytes: number of strings + 80 bytes: maximum absolute filename + 1 byte: '\0' -- 1999/04/21 ska */intvec getvec(unsigned char intno){ intvec iv; disable(); iv = *(intvec FAR *)MK_FP(0,4 * (intno)); enable(); return iv;}void setvec(unsigned char intno, intvec vector){ disable(); *(intvec FAR *)MK_FP(0,4 * intno) = vector; enable();}ULONG SftGetFsize(int sft_idx){ sft FAR *s = idx_to_sft(sft_idx); /* Get the SFT block that contains the SFT */ if (FP_OFF(s) == (size_t) -1) return DE_INVLDHNDL; /* If SFT entry refers to a device, return the date and time of opening */ if (s->sft_flags & (SFT_FDEVICE | SFT_FSHARED)) { return s->sft_size; } /* call file system handler */ return dos_getfsize(s->sft_status);}STATIC COUNT ChildEnv(exec_blk * exp, UWORD * pChildEnvSeg, char far * pathname){ BYTE FAR *pSrc; BYTE FAR *pDest; UWORD nEnvSize; COUNT RetCode;/* UWORD MaxEnvSize; not used -- 1999/04/21 ska */ psp FAR *ppsp = MK_FP(cu_psp, 0); /* create a new environment for the process */ /* copy parent's environment if exec.env_seg == 0 */ pSrc = exp->exec.env_seg ? MK_FP(exp->exec.env_seg, 0) : MK_FP(ppsp->ps_environ, 0);#if 0 /* Every process requires an environment because of argv[0] -- 1999/04/21 ska */ */if (!pSrc) /* no environment to copy */ { *pChildEnvSeg = 0; return SUCCESS; }#endif nEnvSize = 1; /* This loop had not counted the very last '\0' -- 1999/04/21 ska */ if (pSrc) { /* if no environment is available, one byte is required */ for (nEnvSize = 0;; nEnvSize++) { /* Test env size and abort if greater than max */ if (nEnvSize >= MAXENV - ENV_KEEPFREE) return DE_INVLDENV; if (*(UWORD FAR *) (pSrc + nEnvSize) == 0) break; } nEnvSize += 2; /* account for trailing \0\0 */ } /* allocate enough space for env + path */ if ((RetCode = DosMemAlloc((nEnvSize + ENV_KEEPFREE + 15)/16, mem_access_mode, pChildEnvSeg, NULL /*(UWORD FAR *) MaxEnvSize ska */ )) < 0) return RetCode; pDest = MK_FP(*pChildEnvSeg + 1, 0); /* fill the new env and inform the process of its */ /* location throught the psp */ /* copy the environment */ if (pSrc) { fmemcpy(pDest, pSrc, nEnvSize); pDest += nEnvSize; } else *pDest++ = '\0'; /* create an empty environment */ /* initialize 'extra strings' count */ *((UWORD FAR *) pDest) = 1; pDest += sizeof(UWORD) / sizeof(BYTE); /* copy complete pathname */ if ((RetCode = truename(pathname, PriPathName, CDS_MODE_SKIP_PHYSICAL)) < SUCCESS) { return RetCode; } fstrcpy(pDest, PriPathName); /* Theoretically one could either: + resize the already allocated block to best-fit behind the pathname, or + generate the filename into a temporary buffer to allocate only the minimum required environment -- 1999/04/21 ska */ return SUCCESS;}/* The following code is 8086 dependant */void new_psp(seg para, seg cur_psp){ psp FAR *p = MK_FP(para, 0); fmemcpy(p, MK_FP(cur_psp, 0), sizeof(psp)); /* terminate address */ p->ps_isv22 = getvec(0x22); /* break address */ p->ps_isv23 = getvec(0x23); /* critical error address */ p->ps_isv24 = getvec(0x24); /* parent psp segment set to 0 (see RBIL int21/ah=26) */ p->ps_parent = 0;}void child_psp(seg para, seg cur_psp, int psize){ psp FAR *p = MK_FP(para, 0); psp FAR *q = MK_FP(cur_psp, 0); int i; new_psp(para, cur_psp); /* Now for parent-child relationships */ /* parent psp segment */ p->ps_parent = cu_psp; /* previous psp pointer */ p->ps_prevpsp = q; /* Environment and memory useage parameters */ /* memory size in paragraphs */ p->ps_size = psize; /* File System parameters */ /* maximum open files */ p->ps_maxfiles = 20; fmemset(p->ps_files, 0xff, 20); /* open file table pointer */ p->ps_filetab = p->ps_files; /* clone the file table -- 0xff is unused */ for (i = 0; i < 20; i++) if (CloneHandle(i) >= 0) p->ps_files[i] = q->ps_filetab[i]; /* first command line argument */ p->ps_fcb1.fcb_drive = 0; fmemset(p->ps_fcb1.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); /* second command line argument */ p->ps_fcb2.fcb_drive = 0; fmemset(p->ps_fcb2.fcb_fname, ' ', FNAME_SIZE + FEXT_SIZE); /* local command line */ p->ps_cmd.ctCount = 0; p->ps_cmd.ctBuffer[0] = 0xd; /* command tail */}STATIC UBYTE chkdrv(unsigned drive) /* from FCB: 0 = default, 1 = A:, ... */{ if (drive) drive--; /* 0 = A:, 1 = B:, ... */ else drive = default_drive; return get_cds(drive) ? 0 : 0xff; /* return 0 if drive is valid, else 0xff */}STATIC UWORD patchPSP(UWORD pspseg, UWORD envseg, exec_blk FAR * exb, BYTE FAR * fnam){ psp FAR *psp; mcb FAR *pspmcb; int i; BYTE FAR *np; pspmcb = MK_FP(pspseg, 0); ++pspseg; psp = MK_FP(pspseg, 0); /* complete the psp by adding the command line and FCBs */ fmemcpy(&psp->ps_cmd, exb->exec.cmd_line, sizeof(CommandTail)); if (FP_OFF(exb->exec.fcb_1) != 0xffff) { fmemcpy(&psp->ps_fcb1, exb->exec.fcb_1, 16); fmemcpy(&psp->ps_fcb2, exb->exec.fcb_2, 16); } /* identify the mcb as this functions' */ pspmcb->m_psp = pspseg; /* Patch in environment segment, if present, also adjust its MCB */ if (envseg) { ((mcb FAR *) MK_FP(envseg, 0))->m_psp = pspseg; envseg++; } psp->ps_environ = envseg; /* use the file name less extension - left adjusted and */ np = fnam; for (;;) { switch (*fnam++) { case '\0': goto set_name; case ':': case '/': case '\\': np = fnam; } }set_name: for (i = 0; i < 8 && np[i] != '.' && np[i] != '\0'; i++) { pspmcb->m_name[i] = toupper(np[i]); } if (i < 8) pspmcb->m_name[i] = '\0'; /* return value: AX value to be passed based on FCB values */ return chkdrv(psp->ps_fcb1.fcb_drive) | (chkdrv(psp->ps_fcb2.fcb_drive) << 8);}int load_transfer(UWORD ds, exec_blk *exp, UWORD fcbcode, COUNT mode){ psp FAR *p = MK_FP(ds, 0); psp FAR *q = MK_FP(cu_psp, 0); /* Transfer control to the executable */ p->ps_parent = cu_psp; p->ps_prevpsp = q; q->ps_stack = (BYTE FAR *)user_r; user_r->FLAGS &= ~FLG_CARRY; cu_psp = ds; /* process dta */ dta = &p->ps_cmd; if (mode == LOADNGO) { iregs FAR *irp; /* build the user area on the stack */ irp = (iregs FAR *)(exp->exec.stack - sizeof(iregs)); /* start allocating REGs (as in MS-DOS - some demos expect them so --LG) */ /* see http://www.beroset.com/asm/showregs.asm */ irp->DX = irp->ES = irp->DS = ds; irp->CS = FP_SEG(exp->exec.start_addr); irp->SI = irp->IP = FP_OFF(exp->exec.start_addr); irp->DI = FP_OFF(exp->exec.stack); irp->BP = 0x91e; /* this is more or less random but some programs expect 0x9 in the high byte of BP!! */ irp->AX = irp->BX = fcbcode; irp->CX = 0xFF; irp->FLAGS = 0x200; if (InDOS) --InDOS; exec_user(irp, 1); /* We should never be here fatal("KERNEL RETURNED!!!"); */ } /* mode == LOAD */ exp->exec.stack -= 2; *((UWORD FAR *)(exp->exec.stack)) = fcbcode; return SUCCESS;}/* Now find out how many paragraphs are available considering a threshold, trying HIGH then LOW */STATIC int ExecMemLargest(UWORD *asize, UWORD threshold){ int rc; if (mem_access_mode & 0x80) { mem_access_mode &= ~0x80; mem_access_mode |= 0x40; rc = DosMemLargest(asize); mem_access_mode &= ~0x40; /* less memory than the .COM/.EXE file has: try low memory first */ if (rc != SUCCESS || *asize < threshold) rc = DosMemLargest(asize); mem_access_mode |= 0x80; } else rc = DosMemLargest(asize); return (*asize < threshold ? DE_NOMEM : rc);}STATIC int ExecMemAlloc(UWORD size, seg *para, UWORD *asize){ /* We can still get an error on first fit if the above */ /* returned size was a best fit case */ /* ModeLoadHigh = 80 = try high, then low */ int rc = DosMemAlloc(size, mem_access_mode, para, asize); if (rc != SUCCESS) { if (rc == DE_NOMEM) { rc = DosMemAlloc(0, LARGEST, para, asize); if ((mem_access_mode & 0x80) && (rc != SUCCESS)) { mem_access_mode &= ~0x80; rc = DosMemAlloc(0, LARGEST, para, asize); mem_access_mode |= 0x80; } } } else { /* with no error, we got exactly what we asked for */ *asize = size; } /* This should never happen, but ... */ if (rc == SUCCESS && *asize < size) { DosMemFree(*para); return DE_NOMEM; } return rc;}COUNT DosComLoader(BYTE FAR * namep, exec_blk * exp, COUNT mode, COUNT fd){ UWORD mem; UWORD env, asize = 0; { UWORD com_size; { ULONG com_size_long = SftGetFsize(fd); /* maximally 64k - 256 bytes stack - 256 bytes psp */ com_size = ((UWORD)min(com_size_long, 0xfe00u) >> 4) + 0x10; } if ((mode & 0x7f) != OVERLAY)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -