2 MMURTL Operating System Source Code
\r
3 Copyright 1991,1992,1993,1994 Richard A. Burgess
\r
8 /* This file contains functions and data used to support
\r
9 loading or terminating jobs (or services).
\r
10 It contains the public functions:
\r
12 Chain() Loads new job run file in current JCB & PD
\r
13 LoadNewJob() Loads a new job into a new JCB & PD
\r
14 ExitJob() Exits current job, loads ExitJob if specified
\r
16 GetExitJob() Gets run file name that will be loaded upon ExitJob
\r
17 SetExitJob() Sets run file name to load upon ExitJob
\r
19 SetCmdLine() Sets the command line for next job
\r
20 GetCmdLine() Gets the command line for the current job
\r
22 GetPath() Gets the path prefix for the current job
\r
23 Setpath() Sets the path prefix for the current job
\r
25 SetUserName() Sets the Username for the current job
\r
26 GetUserName() Gets the Username for the current job
\r
31 #define U32 unsigned long
\r
33 #define U16 unsigned int
\r
35 #define U8 unsigned char
\r
40 #include "MKernel.h"
\r
41 #include "MMemory.h"
\r
49 #include "runfile.h"
\r
51 #define MEMUSERD 7 /* User Writable (Data) */
\r
53 #define ErcOpCancel 4 /* Operator cancel */
\r
54 #define ErcOutOfRange 10 /* Bad Exchange specified in OS call */
\r
55 #define ErcBadJobNum 70 /* A Bad job number was specified */
\r
56 #define ErcNoExitJob 76 /* No ExitJob specified on ExitJob(n)*/
\r
57 #define ErcBadRunFile 74 /* Couldn't load specified ExitRunFile */
\r
59 /* Near Support Calls from JobCode.ASM */
\r
61 extern long AllocJCB(long *pdJobNumRet, char *ppJCBRet);
\r
62 extern long RemoveRdyJob(char *pJCB);
\r
63 extern long GetExchOwner(long Exch, char *pJCBRet);
\r
64 extern long SetExchOwner(long Exch, char *pNewJCB);
\r
65 extern long SendAbort(long JobNum, long Exch);
\r
67 /* Temporary NEAR externals from the monitor program for debugging */
\r
69 extern long xprintf(char *fmt, ...);
\r
70 extern U32 Dump(unsigned char *pb, long cb);
\r
72 /* We switch to this stack when we clean out a user
\r
73 PD before we rebuild it.
\r
76 static long TmpStack[128]; /* 512 byte temporary stack */
\r
78 /* Used for allocating/filling in new JCB */
\r
80 static struct JCBRec *pNewJCB; /* Used to access a JCB */
\r
81 static struct JCBRec *pTmpJCB;
\r
82 static struct JCBRec *pCrntJCB;
\r
86 /* For ExitJob and Chain cause They can't have local vars! */
\r
88 static long JobNumE, job_fhE;
\r
89 static long ExchE, ercE, iE;
\r
90 static long BogusMsg[2];
\r
92 static char *pExchJCBE
\r
93 static long KeyCodeE;
\r
95 static char aFileE[80];
\r
96 static long cbFileE;
\r
98 extern unsigned long KillExch; /* From the Monitor */
\r
100 /* Run file data */
\r
102 static char *pCode, *pData, *pStack; /* Ptrs in User mem to load to */
\r
103 static long sCode, sData, sStack; /* Size of segments */
\r
104 static unsigned long oCode, oData; /* Offset in file to Code & Data */
\r
106 static long offCode = 0, /* Virtual Offset for Code & Data Segs */
\r
109 static unsigned long nCDFIX = 0,
\r
118 static char *pStart, filetype;
\r
120 static struct tagtype tag;
\r
123 /************* INTERNAL SUPPORT CALLS ******************/
\r
125 /******************************************************
\r
126 This deallocates all user memory in a PD. This is
\r
127 used when we ExitJob to free up all the memory.
\r
128 We get the pointer to the PD and "walk" through all
\r
129 the User PTs deallocating linear memory. When all
\r
130 PTs have been cleaned, we eliminate the user PDEs.
\r
131 This leaves a blank PD for reuse if needed.
\r
132 NOTE: This must be called from a task that is
\r
133 running in the JCB that owns the memory!
\r
134 ******************************************************/
\r
136 static void CleanUserPD(long *pPD)
\r
139 unsigned long *pPT;
\r
142 for (i=768; i<1024; i++) { /* Look at each shadow PDE */
\r
143 if (pPD[i]) { /* If it's a linear address (non 0)*/
\r
144 pPT = pPD[i] & 0xFFFFF000; /* Point to Page Table */
\r
145 for (j=0; j<1024; j++) {
\r
147 /* Get Beginning address for each run to deallocate */
\r
149 k = 0; /* nPages to deallocate */
\r
150 pMem = ((i-512) * 0x400000) + (j * 4096);
\r
151 while ((pPT[j++]) && (j<1024))
\r
152 k++; /* one more page */
\r
154 { /* we have pages (one or more) */
\r
155 erc = DeAllocPage(pMem, k);
\r
162 /*********************************************************
\r
163 This opens, reads and validates the run file.
\r
164 If all is well, it leaves it open and returns the
\r
165 file handle, else it closes the run file and returns
\r
166 the error to the caller.
\r
167 The caller is responsible for closing the file!!!
\r
168 *********************************************************/
\r
170 static long GetRunFile(char *pFileName, long cbFileName, long *pfhRet)
\r
172 long erc, i, fh, dret;
\r
187 *pfhRet = 0; /* default to 0 */
\r
189 /* Mode Read, Stream type */
\r
190 erc = OpenFile(pFileName, cbFileName, 0, 1, &fh);
\r
192 if (!erc) { /* File opened OK */
\r
195 while ((!erc) && (!fDone)) {
\r
197 erc = ReadBytes (fh, &tag, 5, &dret);
\r
201 erc = ReadBytes (fh, &filetype, 1, &dret);
\r
202 if ((filetype < 1) || (filetype > 3))
\r
203 erc = ErcBadRunFile + 30000;
\r
206 erc = ReadBytes (fh, &sStack, 4, &dret);
\r
207 if (!erc) erc = ReadBytes (fh, &sCode, 4, &dret);
\r
208 if (!erc) erc = ReadBytes (fh, &sData, 4, &dret);
\r
211 erc = ReadBytes (fh, &offData, 4, &dret);
\r
214 erc = ReadBytes (fh, &offCode, 4, &dret);
\r
217 erc = ReadBytes (fh, &pStart, 4, &dret);
\r
220 erc = GetFileLFA(fh, &oCode);
\r
222 erc = SetFileLFA(fh, oCode+tag.len); /* skip it */
\r
225 erc = GetFileLFA(fh, &oData);
\r
227 erc = SetFileLFA(fh, oData+tag.len); /* skip it */
\r
230 erc = GetFileLFA(fh, &oCDFIX);
\r
231 nCDFIX = tag.len/4;
\r
233 erc = SetFileLFA(fh, oCDFIX+tag.len); /* skip it */
\r
236 erc = GetFileLFA(fh, &oCCFIX);
\r
237 nCCFIX = tag.len/4;
\r
239 erc = SetFileLFA(fh, oCCFIX+tag.len); /* skip it */
\r
242 erc = GetFileLFA(fh, &oDDFIX);
\r
243 nDDFIX = tag.len/4;
\r
245 erc = SetFileLFA(fh, oDDFIX+tag.len); /* skip it */
\r
248 erc = GetFileLFA(fh, &oDCFIX);
\r
249 nDCFIX = tag.len/4;
\r
251 erc = SetFileLFA(fh, oDCFIX+tag.len); /* skip it */
\r
257 erc = GetFileLFA(fh, &i);
\r
258 if (tag.len > 1024)
\r
259 erc = ErcBadRunFile;
\r
261 erc = SetFileLFA(fh, i+tag.len); /* skip it */
\r
263 erc = ErcBadRunFile;
\r
277 /********************************************************/
\r
278 /*********** PUBLIC CALLS FOR JOB MANAGEMENT ************/
\r
279 /********************************************************/
\r
281 /**************************************************/
\r
282 long far _SetExitJob(char *pRunFile, long dcbRunFile)
\r
286 GetJobNum(&JobNum);
\r
287 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
288 if (dcbRunFile > 79)
\r
289 return (ErcBadJobParam);
\r
290 else if (!dcbRunFile)
\r
291 pTmpJCB->JcbExitRF[0] = 0;
\r
293 CopyData(pRunFile, &pTmpJCB->JcbExitRF[1], dcbRunFile);
\r
294 pTmpJCB->JcbExitRF[0] = dcbRunFile;
\r
299 /**************************************************/
\r
300 long far _GetExitJob(char *pRunRet, long *pdcbRunRet)
\r
304 GetJobNum(&JobNum);
\r
305 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
306 i = pTmpJCB->JcbExitRF[0];
\r
308 CopyData(&pTmpJCB->JcbExitRF[1], pRunRet, i);
\r
313 /**************************************************/
\r
314 long far _SetPath(char *pPath, long dcbPath)
\r
318 GetJobNum(&JobNum);
\r
319 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
321 return (ErcBadJobParam);
\r
323 pTmpJCB->sbPath[0] = 0;
\r
325 CopyData(pPath, &pTmpJCB->sbPath[1], dcbPath);
\r
326 pTmpJCB->sbPath[0] = dcbPath;
\r
331 /**************************************************/
\r
332 long far _GetPath(long JobNum, char *pPathRet, long *pdcbPathRet)
\r
336 erc = GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to JobNum */
\r
338 i = pTmpJCB->sbPath[0];
\r
340 CopyData(&pTmpJCB->sbPath[1], pPathRet, i);
\r
345 /**************************************************/
\r
346 long far _SetCmdLine(char *pCmd, long dcbCmd)
\r
350 GetJobNum(&JobNum);
\r
351 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
353 return (ErcBadJobParam);
\r
355 pTmpJCB->JcbCmdLine[0] = 0;
\r
357 CopyData(pCmd, &pTmpJCB->JcbCmdLine[1], dcbCmd);
\r
358 pTmpJCB->JcbCmdLine[0] = dcbCmd;
\r
363 /**************************************************/
\r
364 long far _GetCmdLine(char *pCmdRet, long *pdcbCmdRet)
\r
368 GetJobNum(&JobNum);
\r
369 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
370 i = pTmpJCB->JcbCmdLine[0];
\r
372 CopyData(&pTmpJCB->JcbCmdLine[1], pCmdRet, i);
\r
378 /**************************************************/
\r
379 long far _SetUserName(char *pUser, long dcbUser)
\r
383 GetJobNum(&JobNum);
\r
384 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
386 return (ErcBadJobParam);
\r
388 pTmpJCB->sbUserName[0] = 0;
\r
390 CopyData(pUser, &pTmpJCB->sbUserName[1], dcbUser);
\r
391 pTmpJCB->sbUserName[0] = dcbUser;
\r
396 /**************************************************/
\r
397 long far _GetUserName(char *pUserRet, long *pdcbUserRet)
\r
401 GetJobNum(&JobNum);
\r
402 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
403 i = pTmpJCB->sbUserName[0];
\r
405 CopyData(&pTmpJCB->sbUserName[1], pUserRet, i);
\r
410 /**************************************************/
\r
411 long far _SetSysIn(char *pName, long dcbName)
\r
415 GetJobNum(&JobNum);
\r
416 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
417 if ((dcbName > 49) || (!dcbName))
\r
418 return (ErcBadJobParam);
\r
420 CopyData(pName, &pTmpJCB->JcbSysIn[1], dcbName);
\r
421 pTmpJCB->JcbSysIn[0] = dcbName;
\r
426 /**************************************************/
\r
427 long far _GetSysIn(char *pFileRet, long *pdcbFileRet)
\r
431 GetJobNum(&JobNum);
\r
432 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
433 i = pTmpJCB->JcbSysIn[0];
\r
435 CopyData(&pTmpJCB->JcbSysIn[1], pFileRet, i);
\r
440 /**************************************************/
\r
441 long far _SetSysOut(char *pName, long dcbName)
\r
445 GetJobNum(&JobNum);
\r
446 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
447 if ((dcbName > 49) || (!dcbName))
\r
448 return (ErcBadJobParam);
\r
450 CopyData(pName, &pTmpJCB->JcbSysOut[1], dcbName);
\r
451 pTmpJCB->JcbSysOut[0] = dcbName;
\r
456 /**************************************************/
\r
457 long far _GetSysOut(char *pFileRet, long *pdcbFileRet)
\r
461 GetJobNum(&JobNum);
\r
462 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
463 i = pTmpJCB->JcbSysOut[0];
\r
465 CopyData(&pTmpJCB->JcbSysOut[1], pFileRet, i);
\r
470 /**************************************************/
\r
471 long far _SetJobName(char *pName, long dcbName)
\r
474 GetJobNum(&JobNum);
\r
475 GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to current Job */
\r
479 CopyData(pName, &pTmpJCB->sbJobName[1], dcbName);
\r
480 pTmpJCB->sbJobName[0] = dcbName;
\r
484 /*********************************************************
\r
485 This creates and loads a new Job from a RUN file.
\r
486 This returns ErcOK and new job number if loaded OK
\r
487 else an error is returned.
\r
488 *********************************************************/
\r
490 long far _LoadNewJob(char *pFileName, long cbFileName, long *pJobNumRet)
\r
492 long erc, i, fh, dret, nPages;
\r
493 unsigned long *pPD, *pPT, *pVid, *pOSPD;
\r
498 erc = GetRunFile(pFileName, cbFileName, &fh);
\r
502 /* We set these to zero so we can tell if they have
\r
503 been allocated in case we fail so we know what to deallocate
\r
512 erc = AllocJCB(&JobNum, &pNewJCB);
\r
514 /* Alloc OS memory pages required for new job */
\r
517 erc = AllocOSPage(3, &pPD); /* Job's PD, PT * pVirtVid */
\r
519 pPT = pPD + 4096; /* 1 page later */
\r
520 pVid = pPD + 8192; /* 2 pages later */
\r
523 FillData(pPT, 4096, 0); /* Zero user PT */
\r
524 FillData(pVid, 4096, 0); /* Zero user video */
\r
526 GetpJCB(1, &pTmpJCB); /* Get OS pJCB */
\r
527 pOSPD = pTmpJCB->pJcbPD; /* Pointer to OS PD */
\r
529 GetPhyAdd(1, pPT, &PhyAdd); /* Get Phy Add for new PT */
\r
531 PhyAdd |= MEMUSERD; /* Set user code bits in PDE */
\r
533 pOSPD[256] = PhyAdd; /* Make User PDE in OS PD */
\r
534 pOSPD[768] = pPT; /* Shadow Linear Address of PT */
\r
536 /* for serious troubleshooting...
\r
537 xprintf("pOSPD : %08x\r\n", pOSPD);
\r
538 xprintf("pUserPD: %08x\r\n", pPD);
\r
539 xprintf("pUserPT: %08x\r\n", pPT);
\r
540 xprintf("PhyAdd : %08x\r\n", PhyAdd);
\r
541 ReadKbd(&KeyCodeE, 1);
\r
544 /* Now we can allocate User Job Memory */
\r
545 /* Allocate user memory for Stack Code and Data */
\r
546 /* This is STILL done in the OS PD */
\r
548 nPages = sStack/4096;
\r
549 if (sStack%4096) nPages++;
\r
550 erc = AllocPage(nPages, &pStack);
\r
551 sStack = nPages * 4096; /* set to whole pages */
\r
553 nPages = sCode/4096;
\r
554 if (sCode%4096) nPages++;
\r
556 erc = AllocPage(nPages, &pCode);
\r
558 nPages = sData/4096;
\r
559 if (sData%4096) nPages++;
\r
561 erc = AllocPage(nPages, &pData);
\r
563 /* Right now, the OS PD looks exacly like we want
\r
564 the User PD to look. We will now copy the entire
\r
565 OS PD into the User's New PD.
\r
568 CopyData(pOSPD, pPD, 4096); /* Copy OS PD to User PD */
\r
570 /* All Job memory is now allocated, so let's LOAD IT! */
\r
573 erc = SetFileLFA(fh, oCode);
\r
575 erc = ReadBytes (fh, pCode, sCode, &dret);
\r
578 erc = SetFileLFA(fh, oData);
\r
580 erc = ReadBytes (fh, pData, sData, &dret);
\r
582 /* Now that we have read in the code and data we
\r
583 apply fixups to these segments from the runfile
\r
589 erc = SetFileLFA(fh, oCDFIX); /* back to fixups */
\r
590 while ((nCDFIX--) && (!erc)) {
\r
591 erc = ReadBytes (fh, &i, 4, &dret);
\r
592 pFix = pCode + i; /* Where in CSeg */
\r
593 *pFix = *pFix - offData + pData;
\r
598 erc = SetFileLFA(fh, oCCFIX); /* back to fixups */
\r
599 while ((nCCFIX--) && (!erc)) {
\r
600 erc = ReadBytes (fh, &i, 4, &dret);
\r
601 pFix = pCode + i; /* Where in CSeg */
\r
602 *pFix = *pFix - offCode + pCode;
\r
607 erc = SetFileLFA(fh, oDCFIX); /* back to fixups */
\r
608 while ((nDCFIX--) && (!erc)) {
\r
609 erc = ReadBytes (fh, &i, 4, &dret);
\r
610 pFix = pData + i; /* Where in DSeg */
\r
611 *pFix = *pFix - offCode + pCode;
\r
616 erc = SetFileLFA(fh, oDDFIX); /* back to fixups */
\r
617 while ((nDDFIX--) && (!erc)) {
\r
618 erc = ReadBytes (fh, &i, 4, &dret);
\r
619 pFix = pData + i; /* Where in DSeg */
\r
620 *pFix = *pFix - offData + pData;
\r
626 /* Clean the OS PD of User memory */
\r
628 FillData(&pOSPD[256], 1024, 0); /* Clean OS PD of User PDEs */
\r
629 FillData(&pOSPD[768], 1024, 0); /* Clean OS PD of User Shadow */
\r
631 /* Now we fill in the rest of the User's JCB */
\r
633 pNewJCB->pJcbPD = pPD; /* Lin Add of PD */
\r
634 pNewJCB->pJcbStack = pStack; /* Add of Stack */
\r
635 pNewJCB->sJcbStack = sStack; /* Size of Code */
\r
636 pNewJCB->pJcbCode = pCode; /* Add of Code */
\r
637 pNewJCB->sJcbCode = sCode; /* Size of Code */
\r
638 pNewJCB->pJcbData = pData; /* Add of Code */
\r
639 pNewJCB->sJcbData = sData; /* Size of Code */
\r
641 pNewJCB->sbUserName[0] = 0; /* Zero UserName */
\r
642 pNewJCB->sbPath[0] = 0; /* No Default path */
\r
643 pNewJCB->JcbExitRF[0] = 0; /* No Exit Run File */
\r
644 pNewJCB->JcbCmdLine[0] = 0; /* No Cmd Line */
\r
646 CopyData("KBD", &pNewJCB->JcbSysIn[1], 3);
\r
647 pNewJCB->JcbSysIn[0] = 3; /* Size */
\r
649 CopyData("VID", &pNewJCB->JcbSysOut[1], 3);
\r
650 pNewJCB->JcbSysOut[0] = 3; /* Size */
\r
652 pNewJCB->pVidMem = pVid; /* Default to Virt Vid */
\r
653 pNewJCB->pVirtVid = pVid; /* Virtual Video memory */
\r
654 pNewJCB->CrntX = 0; /* Vid X Position */
\r
655 pNewJCB->CrntY = 0; /* Vid Y Position */
\r
656 pNewJCB->nCols = 80; /* Columns */
\r
657 pNewJCB->nLines = 25; /* Lines */
\r
659 pNewJCB->VidMode = 0; /* 80x25 VGA Color Text */
\r
660 pNewJCB->fCursOn = 1; /* Cursor On */
\r
661 pNewJCB->fCursType = 0; /* UnderLine */
\r
664 /* Finally, we crank up the new task and schedule it for
\r
668 erc = AllocExch(&i);
\r
671 erc = NewTask(JobNum, 0x18, 25, 0, i,
\r
673 pStart+pCode-offCode);
\r
675 SetExchOwner(i, pNewJCB); /* Exch now belongs to new JCB */
\r
679 } /* read run file OK */
\r
682 *pJobNumRet = JobNum;
\r
687 /*********************************************************
\r
688 This loads a job into an existing PD and JCB. This is
\r
689 called by Chain() and may also be called by ExitJob()
\r
690 if an ExitJob was specified in the current JCB.
\r
691 The PD, pVid & first PT still exist in OS memory.
\r
692 (CleanPD left the first PT for us). ExitJob and Chain
\r
693 are responsible for opening and validating the runfile
\r
694 and setting up the run file variables.
\r
695 *********************************************************/
\r
697 static long LoadJob(char *pJCB, long fh)
\r
699 long erc, i, dret, nPages;
\r
704 /* Allocate user memory for Stack, Code and Data */
\r
705 /* This is done in the context of the USER PD */
\r
707 nPages = sStack/4096;
\r
708 if (sStack%4096) nPages++;
\r
709 erc = AllocPage(nPages, &pStack);
\r
710 sStack = nPages * 4096; /* set to whole pages */
\r
712 nPages = sCode/4096;
\r
713 if (sCode%4096) nPages++;
\r
715 erc = AllocPage(nPages, &pCode);
\r
717 nPages = sData/4096;
\r
718 if (sData%4096) nPages++;
\r
720 erc = AllocPage(nPages, &pData);
\r
722 /* All Job memory is now allocated, so let's LOAD IT! */
\r
725 erc = SetFileLFA(fh, oCode);
\r
727 erc = ReadBytes (fh, pCode, sCode, &dret);
\r
730 erc = SetFileLFA(fh, oData);
\r
732 erc = ReadBytes (fh, pData, sData, &dret);
\r
734 /* Now that we have read in the code and data we
\r
735 apply fixups to these segments from the runfile
\r
740 erc = SetFileLFA(fh, oCDFIX); /* back to fixups */
\r
741 while ((nCDFIX--) && (!erc)) {
\r
742 erc = ReadBytes (fh, &i, 4, &dret);
\r
743 pFix = pCode + i; /* Where in CSeg */
\r
744 *pFix = *pFix - offData + pData;
\r
749 erc = SetFileLFA(fh, oCCFIX); /* back to fixups */
\r
750 while ((nCCFIX--) && (!erc)) {
\r
751 erc = ReadBytes (fh, &i, 4, &dret);
\r
752 pFix = pCode + i; /* Where in CSeg */
\r
753 *pFix = *pFix - offCode + pCode;
\r
758 erc = SetFileLFA(fh, oDCFIX); /* back to fixups */
\r
759 while ((nDCFIX--) && (!erc)) {
\r
760 erc = ReadBytes (fh, &i, 4, &dret);
\r
761 pFix = pData + i; /* Where in DSeg */
\r
762 *pFix = *pFix - offCode + pCode;
\r
767 erc = SetFileLFA(fh, oDDFIX); /* back to fixups */
\r
768 while ((nDDFIX--) && (!erc)) {
\r
769 erc = ReadBytes (fh, &i, 4, &dret);
\r
770 pFix = pData + i; /* Where in DSeg */
\r
771 *pFix = *pFix - offData + pData;
\r
775 /* Now we fill in the rest of the User's JCB */
\r
776 pNewJCB->pJcbStack = pStack; /* Add of Stack */
\r
777 pNewJCB->sJcbStack = sStack; /* Size of Code */
\r
778 pNewJCB->pJcbCode = pCode; /* Add of Code */
\r
779 pNewJCB->sJcbCode = sCode; /* Size of Code */
\r
780 pNewJCB->pJcbData = pData; /* Add of Code */
\r
781 pNewJCB->sJcbData = sData; /* Size of Code */
\r
789 /******************************************************
\r
790 This is started as new task in the context of a
\r
791 job that is being killed off. This is done to allow
\r
792 memory access and also reuse the code for ExitJob
\r
793 in the monitor. This task, it's exchange, and TSS
\r
794 will be reclaimed by the monitor along with the
\r
795 JCB and all OS memory pages for the PD,PT and video.
\r
796 ******************************************************/
\r
798 void _KillTask(void)
\r
801 GetJobNum(&JobNumE);
\r
802 GetpJCB(JobNumE, &pTmpJCB); /* Get pJCB to this Job */
\r
804 /* Clean the PD of all user memory leaving OS memory to be
\r
805 deallocated by the caller (monitor or whoever).
\r
808 pPDE = pTmpJCB->pJcbPD;
\r
811 GetTSSExch(&ExchE);
\r
814 while(!ercE) /* clear the exchange */
\r
815 ercE = CheckMsg(ExchE, BogusMsg);
\r
817 ISendMsg(KillExch, ExchE, ErcOpCancel);
\r
819 WaitMsg(ExchE, BogusMsg);
\r
821 while(1); /* in case we get scheduled again RAB */
\r
823 /* He's History! */
\r
827 /******************************************************
\r
828 This called from one job to kill another job or
\r
829 service. This cleans up ALL resources that the
\r
831 This is used to kill run-away jobs, or terminate a
\r
832 job just for the fun ot it.
\r
833 It results in a violent death for the job specified.
\r
834 This must never be called from a task within the job
\r
835 to be killed. A job may terminate itself with ExitJob().
\r
836 ******************************************************/
\r
838 long far _KillJob(long JobNum)
\r
841 /* Make sure it's not the Monitor, Debugger or the current job. */
\r
843 GetJobNum(&JobNumE);
\r
844 if ((JobNum == JobNumE) ||
\r
848 return(ErcBadJobNum);
\r
850 erc = GetpJCB(JobNum, &pTmpJCB); /* Get pJCB to the Job */
\r
854 pTmpJCB->ExitError = ErcOpCancel; /* Operator said DIE! */
\r
856 /* Remove ALL tasks for this job that are at the ReadyQue.
\r
857 The task we are in does not belong to the job we are
\r
858 killing so we can remove them all.
\r
861 RemoveRdyJob(pTmpJCB); /* It always returns ErcOk */
\r
863 /* Deallocate ALL exchanges for this job */
\r
867 while (ercE != ErcOutOfRange)
\r
869 ercE = GetExchOwner(iE, &pExchJCBE);
\r
870 if ((!ercE) && (pExchJCBE == pTmpJCB))
\r
874 ercE = 0; /* Clear the error */
\r
876 /* Now that the user can't make anymore requests,
\r
877 We send "Abort" messages to all services.
\r
878 This closes all files that were opened by the Job
\r
879 and frees up any other resources held for this
\r
880 job by any service.
\r
882 We will allocate one exchange for the job
\r
883 that is being killed so we can use it for SendAbort
\r
884 and also as the exchange number we send to the
\r
885 KillExch in the monitor which will kill of the JCB
\r
886 completely (he also switches video and keyboard
\r
890 erc = AllocExch(&ExchE); /* Get an Exch */
\r
891 SetExchOwner(ExchE, pTmpJCB); /* make him the owner */
\r
892 SendAbort(JobNum, ExchE); /* Notify all services */
\r
894 /*JobNum, CodeSeg, Priority, fDebug, Exch, ESP, EIP */
\r
895 erc = NewTask(JobNum, 0x08, 3, 0, ExchE, &TmpStack[127], &_KillTask);
\r
898 /* He's History! */
\r
901 /******************************************************
\r
902 This called from Exit() in C or directly from a user
\r
903 job or service. This cleans up ALL resources that the
\r
905 This also checks for an exit run file to load if
\r
906 one is specified. If no exit run file is specified
\r
907 we just kill the JCB entirely and if video and
\r
908 keyboard are assigned we assign them to the Monitor.
\r
909 ******************************************************/
\r
911 void far _ExitJob(long dError)
\r
913 /* NO LOCAL VARIABLES BECAUSE WE SWITCH STACKS!! */
\r
915 GetJobNum(&JobNumE);
\r
916 GetpJCB(JobNumE, &pCrntJCB); /* Get pJCB to current Job */
\r
917 pCrntJCB->ExitError = dError;
\r
919 /* Remove ALL tasks for this job that are at the ReadyQue.
\r
920 The task we are in won't be removed because its RUNNING!
\r
923 RemoveRdyJob(pCrntJCB); /* It always returns ErcOk */
\r
925 /* Deallocate all exchanges for this job except the one belonging
\r
926 to current TSS! The Dealloc Exchange call will invalidate
\r
927 all TSSs found at exchanges belonging to this user, and
\r
928 will also free up RQBs and Link Blocks. The job will not be
\r
929 able to initiate requests or send messages after this unless
\r
930 it is done with the TSSExchange because it will get a kernel
\r
931 error (invalid exchange).
\r
934 /* Find out what our TSS exchange is so
\r
935 we don't deallocate it to! We need it. */
\r
937 GetTSSExch(&ExchE);
\r
941 while (ercE != ErcOutOfRange)
\r
943 ercE = GetExchOwner(iE, &pExchJCBE);
\r
944 if ((!ercE) && (iE != ExchE) && (pExchJCBE == pCrntJCB))
\r
949 /* Now that the user can't make anymore requests,
\r
950 Send Abort messages to all services.
\r
951 This closes all files that were opened by the Job
\r
952 and frees up any other resources held for this
\r
953 job by any service.
\r
956 SendAbort(JobNumE, ExchE);
\r
958 ercE = 0; /* Clear the error */
\r
959 while(!ercE) /* clear the exchange */
\r
960 ercE = CheckMsg(ExchE, BogusMsg);
\r
961 ercE = 0; /* Clear the error */
\r
963 /* We must now switch to a temporary stack so we can
\r
964 clean out the user PD (we are on his stack right now!).
\r
968 MOV EAX, OFFSET _TmpStack
\r
974 /* Clean the PD of all user memory leaving OS memory for next
\r
975 job if there is one.
\r
978 pPDE = pCrntJCB->pJcbPD;
\r
981 /* Look for Exit Run file to load if any exists. If no exit run
\r
982 file, we deallocate the PD and JCB then return to JOB 1. */
\r
984 GetExitJob(aFileE, &cbFileE); /* Exit Run File!! */
\r
987 ercE = ErcNoExitJob;
\r
990 ercE = GetRunFile(aFileE, cbFileE, &job_fhE);
\r
993 ercE = LoadJob(pCrntJCB, job_fhE);
\r
997 pStart = pStart+pCode-offCode;
\r
999 /* Now we RETURN to new job's address after we put him
\r
1000 on his new stack. */
\r
1012 RETF ;We are history!
\r
1017 if (ercE) { /* something failed or we don't have an ExitRF */
\r
1019 /* In case there is no job to run or a fatal error has happened
\r
1020 we send a message (ISendMsg) to the monitor status
\r
1021 task with our TSSExch and the Error. Then he will WIPE US OUT!
\r
1022 We use ISend (vice send) so he can't run before we get to
\r
1023 the exchange otherwise we will be placed back on the readyQueue!
\r
1026 ISendMsg(KillExch, ExchE, ercE);
\r
1028 WaitMsg(ExchE, BogusMsg);
\r
1030 while(1); /* in case we get scheduled again RAB */
\r
1032 /* We are NO MORE */
\r
1036 /******************************************************
\r
1037 This is called to execute a program without changing
\r
1038 the ExitJob. This is so you can run program B from
\r
1039 program A and return to program A when program B is
\r
1040 done. This runs Job B in the "context" of Job A
\r
1041 which means Job B inherits the JCB and PD of job A
\r
1042 so it can use things like the command line and
\r
1043 path that were set up by A.
\r
1044 Information can be passed to Job B by calling
\r
1045 SetCmdLine (if Job B reads it), and also by
\r
1046 setting the ExitError value in the parameter.
\r
1047 Chain will only return to you if there was an
\r
1048 error loading the Job. In other words, if Chain
\r
1049 fails in a critial section we try to load the
\r
1050 ExitJob and pass it the error.
\r
1051 ******************************************************/
\r
1053 long far _Chain(char *pFileName, long cbFileName, long dExitError)
\r
1055 /* NO LOCAL VARIABLES BECAUSE WE SWITCH STACKS!! */
\r
1057 CopyData(pFileName, aFileE, cbFileName);
\r
1058 cbFileE = cbFileName;
\r
1060 ercE = GetRunFile(pFileName, cbFileName, &job_fhE);
\r
1063 CloseFile(job_fhE); /* if it had a handle at all */
\r
1067 CloseFile(job_fhE); /* we will open it again after SendAbort */
\r
1069 GetJobNum(&JobNumE);
\r
1070 GetpJCB(JobNumE, &pCrntJCB); /* Get pJCB to current Job */
\r
1071 pCrntJCB->ExitError = dExitError;
\r
1073 /* Remove ALL tasks for this job that are at the ReadyQue.
\r
1074 The task we are in won't be removed because its RUNNING!
\r
1077 RemoveRdyJob(pCrntJCB); /* It always returns ErcOk */
\r
1079 /* Deallocate all exchanges for this job except the one belonging
\r
1080 to current TSS! The Dealloc Exchange call will invalidate
\r
1081 all TSSs found at exchanges belonging to this user, and
\r
1082 will also free up RQBs and Link Blocks. The job will not be
\r
1083 able to initiate requests or send messages after this unless
\r
1084 it is done with the TSSExchange because it will get a kernel
\r
1085 error (invalid exchange).
\r
1088 /* Find out what our TSS exchange is so
\r
1089 we don't deallocate it to! */
\r
1091 GetTSSExch(&ExchE);
\r
1095 while (ercE != ErcOutOfRange)
\r
1097 ercE = GetExchOwner(iE, &pExchJCBE);
\r
1098 if ((!ercE) && (iE != ExchE) && (pExchJCBE == pCrntJCB))
\r
1103 /* Now that the user can't make anymore requests,
\r
1104 Send Abort messages to all services.
\r
1105 This closes all files that were opened by the Job
\r
1106 and frees up any other resources held for this
\r
1107 job by any services.
\r
1110 SendAbort(JobNumE, ExchE);
\r
1112 ercE = 0; /* Clear the error */
\r
1113 while(!ercE) /* clear the exchange of abort responses*/
\r
1114 ercE = CheckMsg(ExchE, BogusMsg);
\r
1115 ercE = 0; /* Clear the error */
\r
1117 /* We must now switch to a temporary stack so we can
\r
1118 clean out the user PD (we are on his stack right now!).
\r
1122 MOV EAX, OFFSET _TmpStack
\r
1128 /* Clean the PD of all user memory leaving OS memory for next
\r
1129 job if there is one.
\r
1132 pPDE = pCrntJCB->pJcbPD;
\r
1133 CleanUserPD(pPDE);
\r
1135 /* Try to load the Chain file. Don't bother checking error
\r
1136 cause it was valid if we got here!
\r
1139 GetRunFile(aFileE, cbFileE, &job_fhE); /* it was valid before!*/
\r
1140 ercE = LoadJob(pCrntJCB, job_fhE);
\r
1144 /* We have errored in a critical part of Chain (LoadJob).
\r
1145 The original user's job is destroyed, and we can't run the
\r
1146 chain file (bummer).
\r
1147 The only thing left to do is Look for Exit Run file to load
\r
1148 if any exists. If no exit run file, we kill this guy
\r
1149 and return to the monitor if he had the screen. */
\r
1151 GetExitJob(aFileE, &cbFileE); /* Exit Run File!! */
\r
1154 ercE = ErcNoExitJob;
\r
1157 ercE = GetRunFile(aFileE, cbFileE, &job_fhE);
\r
1160 ercE = LoadJob(pCrntJCB, job_fhE);
\r
1166 pStart = pStart+pCode-offCode;
\r
1168 /* Now we RETURN to new job's address after we put him
\r
1169 on his new stack. */
\r
1181 RETF ;We are history!
\r
1186 { /* Something failed loading the job (Chain or Exit) */
\r
1188 /* In case there is no job to run or a fatal error has happened
\r
1189 we send a message (ISendMsg) to the monitor status
\r
1190 task with our TSSExch and the Error. Then he will WIPE US OUT!
\r
1191 We use ISend (vice send) so he can't run before we get to
\r
1192 the exchange otherwise we will be placed back on the readyQueue!
\r
1195 ISendMsg(KillExch, ExchE, ercE); /* ISend clears ints! */
\r
1200 WaitMsg(ExchE, BogusMsg);
\r
1202 while(1); /* in case we get scheduled again RAB */
\r
1204 /* We are NO MORE */
\r
1209 /*********************** End of Module *****************/
\r