use the toolchain names for the commands
[AROS.git] / rom / dos / createnewproc.c
blobd2264d6110d920ff7bc70d47d336afca2795b4db
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Create a new process
6 Lang: English
7 */
9 #include <aros/debug.h>
11 #include <exec/memory.h>
12 #include <exec/lists.h>
13 #include <proto/exec.h>
14 #include <dos/dosextens.h>
15 #include <dos/dostags.h>
16 #include <dos/stdio.h>
17 #include <proto/dos.h>
18 #include <utility/tagitem.h>
19 #include <intuition/intuition.h>
20 #include <aros/symbolsets.h>
21 #include <proto/utility.h>
22 #include <proto/intuition.h>
23 #include <proto/graphics.h>
24 #include "dos_intern.h"
25 #include LC_LIBDEFS_FILE
26 #include <string.h>
28 #define SEGARRAY_LENGTH 6 /* Minimum needed for HUNK overlays */
30 static void DosEntry(void);
31 static void freeLocalVars(struct Process *process, struct DosLibrary *DOSBase);
32 static BPTR OpenNIL(struct DosLibrary *DOSBase);
34 BOOL copyVars(struct Process *fromProcess, struct Process *toProcess, struct DosLibrary * DOSBase);
36 void internal_ChildWait(struct Task *task, struct DosLibrary * DOSBase);
37 void internal_ChildFree(APTR tid, struct DosLibrary * DOSBase);
39 /*****************************************************************************
41 NAME */
42 #include <proto/dos.h>
44 AROS_LH1(struct Process *, CreateNewProc,
46 /* SYNOPSIS */
47 AROS_LHA(const struct TagItem *, tags, D1),
49 /* LOCATION */
50 struct DosLibrary *, DOSBase, 83, Dos)
52 /* FUNCTION
53 Create a new process using the tagitem array.
55 INPUTS
56 tags - information on the new process.
58 RESULT
59 Pointer to the new process or NULL on error.
61 NOTES
62 It is possible to supply NP_Input, NP_Output and NP_Error tags
63 with BNULL values. This is equal to NIL: handle, however if NP_Input
64 is set to BNULL, NP_Arguments tag will not work. Arguments are
65 passed to the process via input stream, and the stream needs
66 to be a valid handle for this. This is original AmigaOS(tm) feature.
68 EXAMPLE
70 BUGS
72 SEE ALSO
74 INTERNALS
76 *****************************************************************************/
78 AROS_LIBFUNC_INIT
80 /* Allocated resources */
81 struct Process *process = NULL;
82 BPTR input = 0, output = 0, ces = 0, curdir = 0, homedir = 0, segList, *segArray;
83 STRPTR stack = NULL, name = NULL, argptr = NULL;
84 ULONG namesize = 0, argsize = 0;
85 struct MemList *memlist = NULL;
86 struct CommandLineInterface *cli = NULL;
87 struct Process *me = (struct Process *)FindTask(NULL);
88 ULONG old_sig = 0;
89 APTR entry;
91 /* TODO: NP_CommandName */
93 #define TAGDATA_NOT_SPECIFIED ~0ul
95 struct TagItem defaults[]=
97 /* 0 */ { NP_Seglist , 0 },
98 /* 1 */ { NP_Entry , (IPTR)NULL },
99 /* 2 */ { NP_Input , TAGDATA_NOT_SPECIFIED },
100 /* 3 */ { NP_CloseInput , 1 },
101 /* 4 */ { NP_Output , TAGDATA_NOT_SPECIFIED },
102 /* 5 */ { NP_CloseOutput , 1 },
103 /* 6 */ { NP_Error , TAGDATA_NOT_SPECIFIED },
104 /* 7 */ { NP_CloseError , 1 },
105 /* 8 */ { NP_CurrentDir , TAGDATA_NOT_SPECIFIED },
106 /* 9 */ { NP_StackSize , AROS_STACKSIZE },
107 /*10 */ { NP_Name , (IPTR)"New Process" },
108 /*11 */ { NP_Priority , me->pr_Task.tc_Node.ln_Pri },
109 /*12 */ { NP_Arguments , TAGDATA_NOT_SPECIFIED },
110 /*13 */ { NP_Cli , 0 },
111 /*14 */ { NP_UserData , (IPTR)NULL },
112 /*15 */ { NP_ExitCode , (IPTR)NULL },
113 /*16 */ { NP_ExitData , (IPTR)NULL },
114 /*17 */ { NP_WindowPtr , 0 }, /* Default: default public screen */
115 /*18 */ { NP_CopyVars , (IPTR)TRUE },
116 /*19 */ { NP_Synchronous , (IPTR)FALSE },
117 /*20 */ { NP_FreeSeglist , (IPTR)TRUE },
118 /*21 */ { NP_HomeDir , TAGDATA_NOT_SPECIFIED },
119 /*22 */ { NP_Path , TAGDATA_NOT_SPECIFIED }, /* Default: copy path from parent */
120 /*23 */ { NP_NotifyOnDeath , (IPTR)FALSE },
121 /*24 */ { NP_ConsoleTask , TAGDATA_NOT_SPECIFIED },
122 { TAG_END , 0 }
125 /* C has no exceptions. This is a simple replacement. */
126 #define ERROR_IF(a) if(a) goto error /* Throw a generic error. */
127 #define ENOMEM_IF(a) if (a) goto enomem /* Throw out of memory. */
129 D(bug("[createnewproc] Called from %s %s\n", __is_process(me) ? "Process" : "Task", me->pr_Task.tc_Node.ln_Name));
131 /* Inherit the parent process' stacksize if possible */
132 if (__is_process(me))
134 struct CommandLineInterface *cli = Cli();
136 if (cli)
138 LONG parentstack = cli->cli_DefaultStack * CLI_DEFAULTSTACK_UNIT;
140 D(bug("[createnewproc] Parent stack: %u (0x%08X)\n", parentstack, parentstack));
141 if (parentstack > AROS_STACKSIZE)
143 defaults[9].ti_Data = parentstack;
147 if (me->pr_WindowPtr == (APTR)-1)
148 defaults[17].ti_Data = -1;
151 ApplyTagChanges(defaults, (struct TagItem *)tags);
154 int i;
155 for (i = 0; defaults[i].ti_Tag; i++)
156 bug("'%s' %2d: %08x = %08x\n", defaults[10].ti_Data, i, defaults[i].ti_Tag, defaults[i].ti_Data);
161 * If both the seglist and the entry are specified, make sure that the entry resides in the seglist
162 * Disabled because it is not necessarily always true. At least current implementation of SystemTagList()
163 * specifies seglist for the shell but uses own entry point.
165 if (defaults[0].ti_Data && defaults[1].ti_Data)
167 BPTR seg;
169 for (seg = (BPTR) defaults[0].ti_Data; seg; seg = *(BPTR *)BADDR(seg))
173 (UBYTE *)defaults[1].ti_Data >= (UBYTE *)BADDR(seg) &&
174 (UBYTE *)defaults[1].ti_Data <= ((UBYTE *)BADDR(seg) + *((ULONG *)BADDR(seg) - 1) - sizeof(BPTR))
177 break;
181 if (!seg)
182 return NULL;
183 } */
186 * We allocate from the 31bit area because SDL's thread
187 * support requires that the thread ID be 32 bit.
188 * !!! URGENT FIXME !!! SDL MUST BE FIXED!!! Consider using ETask->et_UniqueID for this.
189 * Some architectures (Darwin 64-bit hosted) do not have MEMF_31BIT memory at all.
190 * Additionally, it's horribly bad practice to support broken software this way.
192 #if __WORDSIZE > 32
193 process = AllocMem(sizeof(struct Process), MEMF_PUBLIC | MEMF_31BIT | MEMF_CLEAR);
194 if (!process)
195 #endif
196 process = AllocMem(sizeof(struct Process), MEMF_PUBLIC | MEMF_CLEAR);
197 ENOMEM_IF(process == NULL);
199 /* Do this early to ease implementation of failure code */
200 NEWLIST((struct List *)&process->pr_LocalVars);
203 * This assignment will explicitly convert stack size from IPTR to ULONG.
204 * This is important on 64-bit machines. For example, let's have a tag item:
205 * NP_StackSize, 8192
206 * When this pair is put on stack, numbers are considered LONGs. But items on stack
207 * must be aligned on 8-byte boundaries. So we skip some spacing:
208 * movl $0x2000,0x8(%rsp)
209 * movl $0x800003f3,(%rsp)
210 * Note that since numbers are plain longs, they are loaded using movl operation.
211 * This means that empty space at 0x4(%rsp) will contain trash (leftover from previous
212 * stack usage).
213 * So, if you then grab this value as IPTR, upper half of this value will contain trash.
214 * This way 0x2000 may become something like 0x2000002000, and seriously spoil your life.
215 * Yes, 64-bit systems appear to be strictly typed in such places.
217 process->pr_StackSize = defaults[9].ti_Data;
218 /* We need a minimum stack to handle interrupt contexts */
219 if (process->pr_StackSize < AROS_STACKSIZE)
221 process->pr_StackSize = AROS_STACKSIZE;
224 stack = AllocMem(process->pr_StackSize, MEMF_PUBLIC);
225 ENOMEM_IF(stack == NULL);
227 namesize = strlen((STRPTR)defaults[10].ti_Data) + 1;
228 name = AllocMem(namesize, MEMF_PUBLIC);
229 ENOMEM_IF(name == NULL);
231 /* NP_Arguments */
232 if (defaults[12].ti_Data != TAGDATA_NOT_SPECIFIED)
234 CONST_STRPTR args = (CONST_STRPTR)defaults[12].ti_Data;
236 /* If NULL, then it was provided by the user,
237 * so use the empty "" arg list
239 if (args == NULL)
241 args = "";
244 argsize = strlen(args);
245 argptr = (STRPTR)AllocVec(argsize+1, MEMF_PUBLIC);
246 ENOMEM_IF(argptr == NULL);
247 CopyMem(args, argptr, argsize+1);
249 D(bug("[createnewproc] Arguments \"%s\"\n", argptr));
252 memlist = AllocMem(sizeof(struct MemList) + 2*sizeof(struct MemEntry),
253 MEMF_ANY);
254 ENOMEM_IF(memlist == NULL);
256 /* NP_Cli */
257 if (defaults[13].ti_Data != 0)
259 BPTR oldpath = BNULL;
261 /* Don't forget to pass tags to AllocDosObject() */
262 cli = (struct CommandLineInterface *)AllocDosObject(DOS_CLI, (struct TagItem *)tags);
263 ENOMEM_IF(cli == NULL);
265 cli->cli_DefaultStack = (process->pr_StackSize + CLI_DEFAULTSTACK_UNIT - 1) / CLI_DEFAULTSTACK_UNIT;
267 if (__is_process(me))
269 struct CommandLineInterface *oldcli = Cli();
271 if (oldcli != NULL)
273 LONG oldlen = AROS_BSTR_strlen(oldcli->cli_Prompt);
274 LONG newlen = GetTagData(ADO_PromptLen, 255, tags);
276 oldpath = oldcli->cli_CommandDir;
278 CopyMem(BADDR(oldcli->cli_Prompt), BADDR(cli->cli_Prompt), (newlen<oldlen?newlen:oldlen) + 1);
281 process->pr_CLI = MKBADDR(cli);
282 addprocesstoroot(process, DOSBase);
286 if (defaults[22].ti_Data != TAGDATA_NOT_SPECIFIED)
288 cli->cli_CommandDir = (BPTR) defaults[22].ti_Data;
290 else
292 cli->cli_CommandDir = internal_CopyPath(oldpath, DOSBase);
296 /* NP_Input */
298 if (defaults[2].ti_Data == TAGDATA_NOT_SPECIFIED)
300 input = OpenNIL(DOSBase);
301 ERROR_IF(!input);
303 defaults[2].ti_Data = (IPTR)input;
306 /* NP_Output */
308 if (defaults[4].ti_Data == TAGDATA_NOT_SPECIFIED)
310 output = OpenNIL(DOSBase);
311 ERROR_IF(!output);
313 defaults[4].ti_Data = (IPTR)output;
316 /* NP_Error */
318 if (defaults[6].ti_Data == TAGDATA_NOT_SPECIFIED)
320 ces = OpenNIL(DOSBase);
321 ERROR_IF(!ces);
323 defaults[6].ti_Data = (IPTR)ces;
326 /* NP_CurrentDir */
328 if (defaults[8].ti_Data == TAGDATA_NOT_SPECIFIED)
330 if (__is_process(me) && me->pr_CurrentDir)
332 curdir = Lock("", SHARED_LOCK);
333 ERROR_IF(!curdir);
335 defaults[8].ti_Data = (IPTR)curdir;
337 else
339 defaults[8].ti_Data = 0;
343 /* NP_HomeDir */
345 if (defaults[21].ti_Data == TAGDATA_NOT_SPECIFIED)
347 defaults[21].ti_Data = 0;
349 if (__is_process(me))
351 if (me->pr_HomeDir)
353 homedir = DupLock(me->pr_HomeDir);
354 ERROR_IF(!homedir);
356 defaults[21].ti_Data = (IPTR)homedir;
361 CopyMem((APTR)defaults[10].ti_Data, name, namesize);
363 process->pr_Task.tc_Node.ln_Type = NT_PROCESS;
364 process->pr_Task.tc_Node.ln_Name = name;
365 process->pr_Task.tc_Node.ln_Pri = defaults[11].ti_Data;
366 process->pr_Task.tc_SPLower = stack;
367 process->pr_Task.tc_SPUpper = stack + process->pr_StackSize - SP_OFFSET;
369 D(bug("[createnewproc] Starting process %p '%s'\n", process, name));
370 D(bug("[createnewproc] Stack: 0x%p - 0x%p\n", process->pr_Task.tc_SPLower, process->pr_Task.tc_SPUpper));
372 /* process->pr_ReturnAddr; */
373 NEWLIST(&process->pr_Task.tc_MemEntry);
375 memlist->ml_NumEntries = 3;
376 memlist->ml_ME[0].me_Addr = process;
377 memlist->ml_ME[0].me_Length = sizeof(struct Process);
378 memlist->ml_ME[1].me_Addr = stack;
379 memlist->ml_ME[1].me_Length = process->pr_StackSize;
380 memlist->ml_ME[2].me_Addr = name;
381 memlist->ml_ME[2].me_Length = namesize;
383 AddHead(&process->pr_Task.tc_MemEntry, &memlist->ml_Node);
385 process->pr_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
386 process->pr_MsgPort.mp_Flags = PA_SIGNAL;
387 process->pr_MsgPort.mp_SigBit = SIGB_DOS;
388 process->pr_MsgPort.mp_SigTask = process;
390 NEWLIST(&process->pr_MsgPort.mp_MsgList);
392 process->pr_SegList = BNULL;
393 process->pr_GlobVec = ((struct DosLibrary *)DOSBase)->dl_GV;
394 process->pr_StackBase = MKBADDR(process->pr_Task.tc_SPUpper);
395 process->pr_Result2 = 0;
396 process->pr_CurrentDir = (BPTR)defaults[8].ti_Data;
397 process->pr_CIS = (BPTR)defaults[2].ti_Data;
398 process->pr_COS = (BPTR)defaults[4].ti_Data;
399 process->pr_CES = (BPTR)defaults[6].ti_Data;
400 process->pr_Task.tc_UserData = (APTR)defaults[14].ti_Data;
402 /* Inherit pr_ConsoleTask and pr_FileSystemTask from parent */
403 if (defaults[24].ti_Data != TAGDATA_NOT_SPECIFIED)
404 process->pr_ConsoleTask = (struct MsgPort*)defaults[24].ti_Data;
405 else if (__is_process(me))
406 process->pr_ConsoleTask = me->pr_ConsoleTask;
407 if (__is_process(me))
408 process->pr_FileSystemTask = me->pr_FileSystemTask;
409 else
410 process->pr_FileSystemTask = DOSBase->dl_Root->rn_BootProc;
411 D(bug("[createnewproc] pr_ConsoleTask = %p\n", process->pr_ConsoleTask));
412 D(bug("[createnewproc] pr_FileSystemTask = %p\n", process->pr_FileSystemTask));
415 /* Set the name of this program */
416 internal_SetProgramName(cli, name, DOSBase);
417 D(bug("[createnewproc] Calling internal_SetProgramName() with name = %s\n", name));
419 process->pr_PktWait = NULL;
420 process->pr_WindowPtr = (struct Window *)defaults[17].ti_Data;
421 process->pr_HomeDir = (BPTR)defaults[21].ti_Data;
422 process->pr_Flags = (defaults[3].ti_Data ? PRF_CLOSEINPUT : 0) |
423 (defaults[5].ti_Data ? PRF_CLOSEOUTPUT : 0) |
424 (defaults[7].ti_Data ? PRF_CLOSEERROR : 0) |
425 (defaults[8].ti_Data ? PRF_FREECURRDIR : 0) |
426 (defaults[13].ti_Data ? PRF_FREECLI : 0) |
427 (defaults[19].ti_Data ? PRF_SYNCHRONOUS : 0) |
428 (defaults[20].ti_Data ? PRF_FREESEGLIST : 0) |
429 (defaults[23].ti_Data ? PRF_NOTIFYONDEATH : 0) |
430 (argptr ? PRF_FREEARGS : 0);
431 process->pr_ExitCode = (APTR)defaults[15].ti_Data;
432 process->pr_ExitData = defaults[16].ti_Data;
433 process->pr_Arguments = argptr;
435 if ((BOOL)defaults[18].ti_Data) /* NP_CopyVars */
437 BOOL res = copyVars(me, process, DOSBase);
439 ENOMEM_IF(res == FALSE);
442 process->pr_ShellPrivate = 0;
445 if (defaults[19].ti_Data)
447 me->pr_Flags |= PRF_WAITINGFORCHILD;
449 old_sig = SetSignal(0L, SIGF_SINGLE) & SIGF_SINGLE;
453 * Allocate and fill in segArray.
454 * Except for m68k, we don't have BCPL ABI, so this is a minimal leftover.
455 * The main thing is 3rd member containing actual segList pointer.
456 * Other values are just for convenience.
458 segList = (BPTR)defaults[0].ti_Data;
459 entry = (APTR)defaults[1].ti_Data;
460 if (segList == BNULL) {
461 segList = CreateSegList(entry);
462 process->pr_Flags |= PRF_FREESEGLIST;
463 } else if (entry == NULL) {
464 entry = BADDR(segList) + sizeof(BPTR);
467 segArray = AllocVec(sizeof(BPTR) * (SEGARRAY_LENGTH+1), MEMF_ANY | MEMF_CLEAR);
468 ENOMEM_IF(segArray == NULL);
470 D(bug("[createnewproc] Creating SegArray %p, segList=%p\n", segArray, BADDR(segList)));
471 segArray[0] = (BPTR)SEGARRAY_LENGTH;
472 segArray[1] = (BPTR)-1; /* 'system' segment */
473 segArray[2] = (BPTR)-2; /* 'dosbase' segment */
474 segArray[3] = segList; /* Program segment */
476 process->pr_SegList = MKBADDR(segArray);
478 /* If we have pr_Arguments *and* we have a Input,
479 * then inject the arguments into the input stream.
481 if (process->pr_Arguments && process->pr_CIS)
483 D(bug("[createnewproc] Injecting %d bytes of arguments @%p into FileHandle @%p\n", argsize, process->pr_Arguments, BADDR(process->pr_CIS)));
484 vbuf_inject(process->pr_CIS, process->pr_Arguments, argsize, DOSBase);
487 /* Do any last-minute SegList fixups */
488 BCPL_Fixup(process);
490 /* Abuse pr_Result2 to point to the *real* entry point */
491 process->pr_Result2 = (SIPTR)entry;
493 /* Use AddTask() instead of NewAddTask().
494 * Blizzard SCSI Kit boot ROM plays SetFunction() tricks with
495 * AddTask() and assumes it is called by a process early enough!
497 if (AddTask(&process->pr_Task, DosEntry, NULL))
499 /* Use defaults[19].ti_Data instead of testing against
500 * (process->pr_Flags & PRF_SYNCHRONOUS).
502 * If the priority of the new process is higher than ours,
503 * the new process can be scheduled, completed, and freed
504 * before we get to this check - and we would then be
505 * comparing via a pointer to a stale structure that
506 * may have been overwritten.
508 if (defaults[19].ti_Data)
510 /* If we *are* synchronous, then 'process' is still valid.
512 SIPTR oldSignal = 0;
513 struct FileHandle *fh = NULL;
515 /* Migrate the CIS handle to the new process */
516 if (IsInteractive(process->pr_CIS)) {
517 fh = BADDR(process->pr_CIS);
519 if (dopacket(&oldSignal, fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, (SIPTR)&process->pr_MsgPort, 0, 0, 0, 0, 0) == DOSFALSE)
520 oldSignal = 0;
523 D(bug("[createnewproc] Waiting for task to die...\n"));
524 internal_ChildWait(&me->pr_Task, DOSBase);
526 if (fh && oldSignal) {
527 DoPkt(fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, oldSignal, 0, 0, 0);
531 goto end;
534 /* Fall through */
535 enomem:
537 if (process && process->pr_SegList)
538 FreeVec(BADDR(process->pr_SegList));
540 if (__is_process(me))
542 SetIoErr(ERROR_NO_FREE_STORE);
545 freeLocalVars(process, DOSBase);
547 error:
549 D(bug("[createnewproc] Failed to create process\n"));
551 if (cli != NULL)
553 FreeDosObject(DOS_CLI, cli);
556 if (homedir != BNULL)
558 UnLock(homedir);
561 if (curdir != BNULL)
563 UnLock(curdir);
566 if (output != BNULL)
568 Close(output);
571 if (input != BNULL)
573 Close(input);
576 if (ces != BNULL)
578 Close(ces);
581 FreeVec(argptr);
583 if (memlist != NULL)
585 FreeMem(memlist, sizeof(struct MemList) + 2*sizeof(struct MemEntry));
588 if (name != NULL)
590 FreeMem(name, namesize);
593 if (stack != NULL)
595 FreeMem(stack, process->pr_StackSize);
598 if (process != NULL)
600 FreeMem(process, sizeof(struct Process));
602 process = NULL;
605 end:
607 if (defaults[19].ti_Data)
608 SetSignal(SIGF_SINGLE, old_sig);
610 return process;
612 AROS_LIBFUNC_EXIT
613 } /* CreateNewProc */
615 static void freeLocalVars(struct Process *process, struct DosLibrary *DOSBase)
617 struct LocalVar *varNode;
618 struct Node *tempNode;
620 ForeachNodeSafe(&process->pr_LocalVars,
621 varNode, tempNode)
623 D(bug("Freeing variable %s with value %s at %p\n",
624 varNode->lv_Node.ln_Name, varNode->lv_Value, varNode));
625 FreeMem(varNode->lv_Value, varNode->lv_Len);
626 Remove((struct Node *)varNode);
627 FreeVec(varNode);
631 BPTR internal_CopyPath(BPTR boldpath, struct DosLibrary * DOSBase)
633 BPTR *nextpath, path, *newpath, *oldpath;
635 oldpath = BADDR(boldpath);
637 for (newpath = &path; oldpath != NULL; newpath = nextpath, oldpath = BADDR(oldpath[0])) {
638 /* NOTE: This memory allocation *must* match that which is
639 * done in C:Path!!!!
641 nextpath = AllocVec(2*sizeof(BPTR), MEMF_CLEAR);
642 if (nextpath == NULL)
643 break;
645 *newpath = MKBADDR(nextpath);
646 nextpath[1] = DupLock(oldpath[1]);
647 if (nextpath[1] == BNULL)
648 break;
651 *newpath = BNULL;
653 return path;
656 void internal_ChildWait(struct Task *task, struct DosLibrary * DOSBase)
658 while (((struct Process *)task)->pr_Flags & PRF_WAITINGFORCHILD)
659 Wait(SIGF_SINGLE);
663 void internal_ChildFree(APTR tid, struct DosLibrary * DOSBase)
665 struct Task *task = (struct Task *)tid;
666 struct Process *parent = (struct Process *)(GetETask(task)->et_Parent);
668 D(bug("Awakening the parent task %p (called %s)\n", parent, parent->pr_Task.tc_Node.ln_Name));
670 parent->pr_Flags &= ~PRF_WAITINGFORCHILD;
671 Signal(&parent->pr_Task, SIGF_SINGLE);
675 BOOL copyVars(struct Process *fromProcess, struct Process *toProcess, struct DosLibrary * DOSBase)
677 /* We must have variables to copy... */
678 if (__is_process(fromProcess))
680 struct LocalVar *varNode;
681 struct LocalVar *newVar;
683 /* We use the same strategy as in the ***Var() functions */
684 ForeachNode(&fromProcess->pr_LocalVars, varNode)
686 LONG copyLength = strlen(varNode->lv_Node.ln_Name) + 1 +
687 sizeof(struct LocalVar);
689 newVar = (struct LocalVar *)AllocVec(copyLength,
690 MEMF_PUBLIC | MEMF_CLEAR);
691 if (newVar == NULL)
692 return FALSE;
694 CopyMem(varNode, newVar, copyLength);
695 newVar->lv_Node.ln_Name = (char *)newVar +
696 sizeof(struct LocalVar);
697 D(bug("Variable with name %s copied.\n",
698 newVar->lv_Node.ln_Name));
700 if (varNode->lv_Len)
702 newVar->lv_Value = AllocMem(varNode->lv_Len, MEMF_PUBLIC);
704 if (newVar->lv_Value == NULL)
706 /* Free variable node before shutting down */
707 FreeVec(newVar);
709 return FALSE;
712 CopyMem(varNode->lv_Value, newVar->lv_Value, varNode->lv_Len);
715 AddTail((struct List *)&toProcess->pr_LocalVars,
716 (struct Node *)newVar);
720 return TRUE;
723 static void DosEntry(void)
725 struct Process *me = (struct Process *)FindTask(NULL);
726 LONG result;
727 ULONG argSize = me->pr_Arguments ? strlen(me->pr_Arguments) : 0;
728 APTR DOSBase;
729 APTR initialPC;
730 BPTR *segArray;
731 BPTR cis, cos, ces;
733 /* Save away our current streams */
734 cis = me->pr_CIS;
735 cos = me->pr_COS;
736 ces = me->pr_CES;
738 /* me->pr_Result2 contains our real entry point
740 initialPC = (APTR)me->pr_Result2;
741 me->pr_Result2 = 0;
743 D(bug("[DosEntry %p] is %synchronous\n", me, (me->pr_Flags & PRF_SYNCHRONOUS) ? "S" :"As"));
745 segArray = BADDR(me->pr_SegList);
746 if (initialPC == NULL)
747 initialPC = BADDR(segArray[3]) + sizeof(BPTR);
749 D(bug("[DosEntry %p] entry=%p, CIS=%p, COS=%p, argsize=%d, arguments=\"%s\"\n", me, initialPC, BADDR(me->pr_CIS), BADDR(me->pr_COS), argSize, me->pr_Arguments));
751 /* Call entry point of our process, remembering stack in its pr_ReturnAddr */
752 result = CallEntry(me->pr_Arguments, argSize, initialPC, me);
754 /* Call user defined exit function before shutting down. */
755 if (me->pr_ExitCode != NULL)
758 The Ralph Babel's guru book says that pr_ExitCode
759 is passed the process return code in D0 and pr_ExitData in D1,
760 but the Matt Dillon's DICE C implementation of vfork shows that
761 those parameters are passed also on the stack.
763 #ifdef __mc68000
764 asm volatile (
765 "move.l %0, %%d0\n"
766 "move.l %1, %%d1\n"
767 "move.l %2, %%a0\n"
768 "move.l %%d0, %%sp@-\n"
769 "move.l %%d1, %%sp@-\n"
770 "jsr (%%a0)\n"
771 "addq.l #8, %%sp\n"
772 : /* No return values */
773 : "g" (result), "g" (me->pr_ExitData), "g" (me->pr_ExitCode)
774 : "d0", "d1", "a0", "a1"
776 #else
778 The AROS macros for functions with register parameters don't
779 support both register and stack parameters at once, so we use
780 the stack only on non-m68k. This oughta be fixed somehow.
782 me->pr_ExitCode(result, me->pr_ExitData);
783 #endif
786 /* Get our own private DOSBase. We'll need it for our
787 * cleanup routines.
789 * We don't want to use the parent's DOSBase, since they
790 * may have closed their handle long ago.
792 * With the current DOSBase implementation, this isn't a
793 * big deal, but if DOSBase moved to a per-opener library
794 * in the future, this would be a very subtle issue, so
795 * we're going to plan ahead and do it right.
797 DOSBase = TaggedOpenLibrary(TAGGEDOPEN_DOS);
798 if (DOSBase == NULL) {
799 D(bug("[DosEntry %p] Can't open DOS library\n", me));
800 Alert(AT_DeadEnd | AG_OpenLib | AO_DOSLib);
803 D(bug("Deleting local variables\n"));
805 /* Clean up */
806 freeLocalVars(me, DOSBase);
808 D(bug("Closing input stream\n"));
810 if (me->pr_Flags & PRF_CLOSEINPUT)
812 Close(cis);
815 D(bug("Closing output stream\n"));
817 if (me->pr_Flags & PRF_CLOSEOUTPUT)
819 Close(cos);
822 D(bug("Closing error stream\n"));
824 if (me->pr_Flags & PRF_CLOSEERROR)
826 Close(ces);
829 D(bug("Freeing arguments\n"));
831 if (me->pr_Flags & PRF_FREEARGS)
833 FreeVec(me->pr_Arguments);
836 D(bug("Unloading segment\n"));
838 if (me->pr_Flags & PRF_FREESEGLIST)
840 BPTR *segarray = BADDR(me->pr_SegList);
842 if (segarray && segarray[3])
843 UnLoadSeg(segarray[3]);
846 FreeVec(BADDR(me->pr_SegList));
848 if (me->pr_GlobVec && me->pr_GlobVec != ((struct DosLibrary *)DOSBase)->dl_GV) {
849 D(bug("[DosEntry] Looks like someone screwed up %p's pr_GlobVec (%p != dl_GV of %p)\n", me, me->pr_GlobVec, ((struct DosLibrary *)DOSBase)->dl_GV));
850 D(Alert(AT_DeadEnd | AN_FreeVec));
853 D(bug("Unlocking current dir\n"));
855 if (me->pr_Flags & PRF_FREECURRDIR)
857 UnLock(me->pr_CurrentDir);
860 D(bug("Unlocking home dir\n"));
861 UnLock(me->pr_HomeDir);
863 D(bug("Closing cli_StandardError\n"));
865 if (me->pr_Flags & PRF_CLOSECLIERROR)
867 struct CommandLineInterface *cli = (struct CommandLineInterface *)(BADDR(me->pr_CLI));
868 Close(cli->cli_StandardError); /* See newcliproc.c */
871 D(bug("Freeing cli structure\n"));
873 if (me->pr_Flags & PRF_FREECLI)
875 FreeDosObject(DOS_CLI, BADDR(me->pr_CLI));
876 removefromrootnode(me, DOSBase);
877 me->pr_CLI = BNULL;
880 /* Synchronous completion must be before
881 * PRF_NOTIFYONDEATH, in case both were
882 * enabled.
884 if (me->pr_Flags & PRF_SYNCHRONOUS) {
885 D(bug("Calling ChildFree()\n"));
886 /* ChildFree signals the parent */
887 internal_ChildFree(me, DOSBase);
890 /* Notify of the child's death.
892 if (me->pr_Flags & PRF_NOTIFYONDEATH)
894 Signal(GetETask(me)->et_Parent, SIGF_CHILD);
897 CloseLibrary((APTR)DOSBase);
901 * This is a version of Open("NIL:") that works inside a task.
903 static BPTR OpenNIL(struct DosLibrary *DOSBase)
905 struct FileHandle *fh;
907 if ((fh = (struct FileHandle *)AllocDosObject(DOS_FILEHANDLE,NULL))) {
908 return (BPTR)handleNIL(ACTION_FINDINPUT, (SIPTR)MKBADDR(fh), (SIPTR)NULL, (SIPTR)NULL);
911 return BNULL;