📄 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_STRINGS
static 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 + -