start service tasks separately in-case platforms need to perform additional set-up...
[AROS.git] / rom / dos / createnewproc.c
blob0578fbee071fa0411e0e9a71efe94f1b829e82d6
1 /*
2 Copyright © 1995-2013, 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(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 , (IPTR)NULL }, /* 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;
148 ApplyTagChanges(defaults, (struct TagItem *)tags);
151 int i;
152 for (i = 0; defaults[i].ti_Tag; i++)
153 bug("'%s' %2d: %08x = %08x\n", defaults[10].ti_Data, i, defaults[i].ti_Tag, defaults[i].ti_Data);
158 * If both the seglist and the entry are specified, make sure that the entry resides in the seglist
159 * Disabled because it is not necessarily always true. At least current implementation of SystemTagList()
160 * specifies seglist for the shell but uses own entry point.
162 if (defaults[0].ti_Data && defaults[1].ti_Data)
164 BPTR seg;
166 for (seg = (BPTR) defaults[0].ti_Data; seg; seg = *(BPTR *)BADDR(seg))
170 (UBYTE *)defaults[1].ti_Data >= (UBYTE *)BADDR(seg) &&
171 (UBYTE *)defaults[1].ti_Data <= ((UBYTE *)BADDR(seg) + *((ULONG *)BADDR(seg) - 1) - sizeof(BPTR))
174 break;
178 if (!seg)
179 return NULL;
180 } */
183 * We allocate from the 31bit area because SDL's thread
184 * support requires that the thread ID be 32 bit.
185 * !!! URGENT FIXME !!! SDL MUST BE FIXED!!! Consider using ETask->et_UniqueID for this.
186 * Some architectures (Darwin 64-bit hosted) do not have MEMF_31BIT memory at all.
187 * Additionally, it's horribly bad practice to support broken software this way.
189 #if __WORDSIZE > 32
190 process = AllocMem(sizeof(struct Process), MEMF_PUBLIC | MEMF_31BIT | MEMF_CLEAR);
191 if (!process)
192 #endif
193 process = AllocMem(sizeof(struct Process), MEMF_PUBLIC | MEMF_CLEAR);
194 ENOMEM_IF(process == NULL);
196 /* Do this early to ease implementation of failure code */
197 NEWLIST((struct List *)&process->pr_LocalVars);
200 * This assignment will explicitly convert stack size from IPTR to ULONG.
201 * This is important on 64-bit machines. For example, let's have a tag item:
202 * NP_StackSize, 8192
203 * When this pair is put on stack, numbers are considered LONGs. But items on stack
204 * must be aligned on 8-byte boundaries. So we skip some spacing:
205 * movl $0x2000,0x8(%rsp)
206 * movl $0x800003f3,(%rsp)
207 * Note that since numbers are plain longs, they are loaded using movl operation.
208 * This means that empty space at 0x4(%rsp) will contain trash (leftover from previous
209 * stack usage).
210 * So, if you then grab this value as IPTR, upper half of this value will contain trash.
211 * This way 0x2000 may become something like 0x2000002000, and seriously spoil your life.
212 * Yes, 64-bit systems appear to be strictly typed in such places.
214 process->pr_StackSize = defaults[9].ti_Data;
215 /* We need a minimum stack to handle interrupt contexts */
216 if (process->pr_StackSize < AROS_STACKSIZE)
218 process->pr_StackSize = AROS_STACKSIZE;
221 stack = AllocMem(process->pr_StackSize, MEMF_PUBLIC);
222 ENOMEM_IF(stack == NULL);
224 namesize = strlen((STRPTR)defaults[10].ti_Data) + 1;
225 name = AllocMem(namesize, MEMF_PUBLIC);
226 ENOMEM_IF(name == NULL);
228 /* NP_Arguments */
229 if (defaults[12].ti_Data != TAGDATA_NOT_SPECIFIED)
231 CONST_STRPTR args = (CONST_STRPTR)defaults[12].ti_Data;
233 /* If NULL, then it was provided by the user,
234 * so use the empty "" arg list
236 if (args == NULL)
238 args = "";
241 argsize = strlen(args);
242 argptr = (STRPTR)AllocVec(argsize+1, MEMF_PUBLIC);
243 ENOMEM_IF(argptr == NULL);
244 CopyMem(args, argptr, argsize+1);
246 D(bug("[createnewproc] Arguments \"%s\"\n", argptr));
249 memlist = AllocMem(sizeof(struct MemList) + 2*sizeof(struct MemEntry),
250 MEMF_ANY);
251 ENOMEM_IF(memlist == NULL);
253 /* NP_Cli */
254 if (defaults[13].ti_Data != 0)
256 BPTR oldpath = BNULL;
258 /* Don't forget to pass tags to AllocDosObject() */
259 cli = (struct CommandLineInterface *)AllocDosObject(DOS_CLI, (struct TagItem *)tags);
260 ENOMEM_IF(cli == NULL);
262 cli->cli_DefaultStack = (process->pr_StackSize + CLI_DEFAULTSTACK_UNIT - 1) / CLI_DEFAULTSTACK_UNIT;
264 if (__is_process(me))
266 struct CommandLineInterface *oldcli = Cli();
268 if (oldcli != NULL)
270 LONG oldlen = AROS_BSTR_strlen(oldcli->cli_Prompt);
271 LONG newlen = GetTagData(ADO_PromptLen, 255, tags);
273 oldpath = oldcli->cli_CommandDir;
275 CopyMem(BADDR(oldcli->cli_Prompt), BADDR(cli->cli_Prompt), (newlen<oldlen?newlen:oldlen) + 1);
278 process->pr_CLI = MKBADDR(cli);
279 addprocesstoroot(process, DOSBase);
283 if (defaults[22].ti_Data != TAGDATA_NOT_SPECIFIED)
285 cli->cli_CommandDir = (BPTR) defaults[22].ti_Data;
287 else
289 cli->cli_CommandDir = internal_CopyPath(oldpath, DOSBase);
293 /* NP_Input */
295 if (defaults[2].ti_Data == TAGDATA_NOT_SPECIFIED)
297 input = OpenNIL(DOSBase);
298 ERROR_IF(!input);
300 defaults[2].ti_Data = (IPTR)input;
303 /* NP_Output */
305 if (defaults[4].ti_Data == TAGDATA_NOT_SPECIFIED)
307 output = OpenNIL(DOSBase);
308 ERROR_IF(!output);
310 defaults[4].ti_Data = (IPTR)output;
313 /* NP_Error */
315 if (defaults[6].ti_Data == TAGDATA_NOT_SPECIFIED)
317 ces = OpenNIL(DOSBase);
318 ERROR_IF(!ces);
320 defaults[6].ti_Data = (IPTR)ces;
323 /* NP_CurrentDir */
325 if (defaults[8].ti_Data == TAGDATA_NOT_SPECIFIED)
327 if (__is_process(me) && me->pr_CurrentDir)
329 curdir = Lock("", SHARED_LOCK);
330 ERROR_IF(!curdir);
332 defaults[8].ti_Data = (IPTR)curdir;
334 else
336 defaults[8].ti_Data = 0;
340 /* NP_HomeDir */
342 if (defaults[21].ti_Data == TAGDATA_NOT_SPECIFIED)
344 defaults[21].ti_Data = 0;
346 if (__is_process(me))
348 if (me->pr_HomeDir)
350 homedir = DupLock(me->pr_HomeDir);
351 ERROR_IF(!homedir);
353 defaults[21].ti_Data = (IPTR)homedir;
358 CopyMem((APTR)defaults[10].ti_Data, name, namesize);
360 process->pr_Task.tc_Node.ln_Type = NT_PROCESS;
361 process->pr_Task.tc_Node.ln_Name = name;
362 process->pr_Task.tc_Node.ln_Pri = defaults[11].ti_Data;
363 process->pr_Task.tc_SPLower = stack;
364 process->pr_Task.tc_SPUpper = stack + process->pr_StackSize - SP_OFFSET;
366 D(bug("[createnewproc] Starting process %p '%s'\n", process, name));
367 D(bug("[createnewproc] Stack: 0x%p - 0x%p\n", process->pr_Task.tc_SPLower, process->pr_Task.tc_SPUpper));
369 /* process->pr_ReturnAddr; */
370 NEWLIST(&process->pr_Task.tc_MemEntry);
372 memlist->ml_NumEntries = 3;
373 memlist->ml_ME[0].me_Addr = process;
374 memlist->ml_ME[0].me_Length = sizeof(struct Process);
375 memlist->ml_ME[1].me_Addr = stack;
376 memlist->ml_ME[1].me_Length = process->pr_StackSize;
377 memlist->ml_ME[2].me_Addr = name;
378 memlist->ml_ME[2].me_Length = namesize;
380 AddHead(&process->pr_Task.tc_MemEntry, &memlist->ml_Node);
382 process->pr_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
383 process->pr_MsgPort.mp_Flags = PA_SIGNAL;
384 process->pr_MsgPort.mp_SigBit = SIGB_DOS;
385 process->pr_MsgPort.mp_SigTask = process;
387 NEWLIST(&process->pr_MsgPort.mp_MsgList);
389 process->pr_SegList = BNULL;
390 process->pr_GlobVec = ((struct DosLibrary *)DOSBase)->dl_GV;
391 process->pr_StackBase = MKBADDR(process->pr_Task.tc_SPUpper);
392 process->pr_Result2 = 0;
393 process->pr_CurrentDir = (BPTR)defaults[8].ti_Data;
394 process->pr_CIS = (BPTR)defaults[2].ti_Data;
395 process->pr_COS = (BPTR)defaults[4].ti_Data;
396 process->pr_CES = (BPTR)defaults[6].ti_Data;
397 process->pr_Task.tc_UserData = (APTR)defaults[14].ti_Data;
399 /* Inherit pr_ConsoleTask and pr_FileSystemTask from parent */
400 if (defaults[24].ti_Data != TAGDATA_NOT_SPECIFIED)
401 process->pr_ConsoleTask = (struct MsgPort*)defaults[24].ti_Data;
402 else if (__is_process(me))
403 process->pr_ConsoleTask = me->pr_ConsoleTask;
404 if (__is_process(me))
405 process->pr_FileSystemTask = me->pr_FileSystemTask;
406 else
407 process->pr_FileSystemTask = DOSBase->dl_Root->rn_BootProc;
408 D(bug("[createnewproc] pr_ConsoleTask = %p\n", process->pr_ConsoleTask));
409 D(bug("[createnewproc] pr_FileSystemTask = %p\n", process->pr_FileSystemTask));
412 /* Set the name of this program */
413 internal_SetProgramName(cli, name, DOSBase);
414 D(bug("[createnewproc] Calling internal_SetProgramName() with name = %s\n", name));
416 process->pr_PktWait = NULL;
417 process->pr_WindowPtr = (struct Window *)defaults[17].ti_Data;
418 process->pr_HomeDir = (BPTR)defaults[21].ti_Data;
419 process->pr_Flags = (defaults[3].ti_Data ? PRF_CLOSEINPUT : 0) |
420 (defaults[5].ti_Data ? PRF_CLOSEOUTPUT : 0) |
421 (defaults[7].ti_Data ? PRF_CLOSEERROR : 0) |
422 (defaults[8].ti_Data ? PRF_FREECURRDIR : 0) |
423 (defaults[13].ti_Data ? PRF_FREECLI : 0) |
424 (defaults[19].ti_Data ? PRF_SYNCHRONOUS : 0) |
425 (defaults[20].ti_Data ? PRF_FREESEGLIST : 0) |
426 (defaults[23].ti_Data ? PRF_NOTIFYONDEATH : 0) |
427 (argptr ? PRF_FREEARGS : 0);
428 process->pr_ExitCode = (APTR)defaults[15].ti_Data;
429 process->pr_ExitData = defaults[16].ti_Data;
430 process->pr_Arguments = argptr;
432 if ((BOOL)defaults[18].ti_Data) /* NP_CopyVars */
434 BOOL res = copyVars(me, process, DOSBase);
436 ENOMEM_IF(res == FALSE);
439 process->pr_ShellPrivate = 0;
442 if (defaults[19].ti_Data)
444 me->pr_Flags |= PRF_WAITINGFORCHILD;
446 old_sig = SetSignal(0L, SIGF_SINGLE) & SIGF_SINGLE;
450 * Allocate and fill in segArray.
451 * Except for m68k, we don't have BCPL ABI, so this is a minimal leftover.
452 * The main thing is 3rd member containing actual segList pointer.
453 * Other values are just for convenience.
455 segList = (BPTR)defaults[0].ti_Data;
456 entry = (APTR)defaults[1].ti_Data;
457 if (segList == BNULL) {
458 segList = CreateSegList(entry);
459 process->pr_Flags |= PRF_FREESEGLIST;
460 } else if (entry == NULL) {
461 entry = BADDR(segList) + sizeof(BPTR);
464 segArray = AllocVec(sizeof(BPTR) * (SEGARRAY_LENGTH+1), MEMF_ANY | MEMF_CLEAR);
465 ENOMEM_IF(segArray == NULL);
467 D(bug("[createnewproc] Creating SegArray %p, segList=%p\n", segArray, BADDR(segList)));
468 segArray[0] = (BPTR)SEGARRAY_LENGTH;
469 segArray[1] = (BPTR)-1; /* 'system' segment */
470 segArray[2] = (BPTR)-2; /* 'dosbase' segment */
471 segArray[3] = segList; /* Program segment */
473 process->pr_SegList = MKBADDR(segArray);
475 /* If we have pr_Arguments *and* we have a Input,
476 * then inject the arguments into the input stream.
478 if (process->pr_Arguments && process->pr_CIS)
480 D(bug("[createnewproc] Injecting %d bytes of arguments @%p into FileHandle @%p\n", argsize, process->pr_Arguments, BADDR(process->pr_CIS)));
481 vbuf_inject(process->pr_CIS, process->pr_Arguments, argsize, DOSBase);
484 /* Do any last-minute SegList fixups */
485 BCPL_Fixup(process);
487 /* Abuse pr_Result2 to point to the *real* entry point */
488 process->pr_Result2 = (SIPTR)entry;
490 /* Use AddTask() instead of NewAddTask().
491 * Blizzard SCSI Kit boot ROM plays SetFunction() tricks with
492 * AddTask() and assumes it is called by a process early enough!
494 if (AddTask(&process->pr_Task, DosEntry, NULL))
496 /* Use defaults[19].ti_Data instead of testing against
497 * (process->pr_Flags & PRF_SYNCHRONOUS).
499 * If the priority of the new process is higher than ours,
500 * the new process can be scheduled, completed, and freed
501 * before we get to this check - and we would then be
502 * comparing via a pointer to a stale structure that
503 * may have been overwritten.
505 if (defaults[19].ti_Data)
507 /* If we *are* synchronous, then 'process' is still valid.
509 SIPTR oldSignal = 0;
510 struct FileHandle *fh = NULL;
512 /* Migrate the CIS handle to the new process */
513 if (IsInteractive(process->pr_CIS)) {
514 fh = BADDR(process->pr_CIS);
516 if (dopacket(&oldSignal, fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, (SIPTR)&process->pr_MsgPort, 0, 0, 0, 0, 0) == DOSFALSE)
517 oldSignal = 0;
520 D(bug("[createnewproc] Waiting for task to die...\n"));
521 internal_ChildWait(&me->pr_Task, DOSBase);
523 if (fh && oldSignal) {
524 DoPkt(fh->fh_Type, ACTION_CHANGE_SIGNAL, (SIPTR)fh->fh_Arg1, oldSignal, 0, 0, 0);
528 goto end;
531 /* Fall through */
532 enomem:
534 if (process && process->pr_SegList)
535 FreeVec(BADDR(process->pr_SegList));
537 if (__is_process(me))
539 SetIoErr(ERROR_NO_FREE_STORE);
542 freeLocalVars(process, DOSBase);
544 error:
546 D(bug("[createnewproc] Failed to create process\n"));
548 if (cli != NULL)
550 FreeDosObject(DOS_CLI, cli);
553 if (homedir != BNULL)
555 UnLock(homedir);
558 if (curdir != BNULL)
560 UnLock(curdir);
563 if (output != BNULL)
565 Close(output);
568 if (input != BNULL)
570 Close(input);
573 if (ces != BNULL)
575 Close(ces);
578 FreeVec(argptr);
580 if (memlist != NULL)
582 FreeMem(memlist, sizeof(struct MemList) + 2*sizeof(struct MemEntry));
585 if (name != NULL)
587 FreeMem(name, namesize);
590 if (stack != NULL)
592 FreeMem(stack, process->pr_StackSize);
595 if (process != NULL)
597 FreeMem(process, sizeof(struct Process));
599 process = NULL;
602 end:
604 if (defaults[19].ti_Data)
605 SetSignal(SIGF_SINGLE, old_sig);
607 return process;
609 AROS_LIBFUNC_EXIT
610 } /* CreateNewProc */
612 static void freeLocalVars(struct Process *process, struct DosLibrary *DOSBase)
614 struct LocalVar *varNode;
615 struct Node *tempNode;
617 ForeachNodeSafe(&process->pr_LocalVars,
618 varNode, tempNode)
620 D(bug("Freeing variable %s with value %s at %p\n",
621 varNode->lv_Node.ln_Name, varNode->lv_Value, varNode));
622 FreeMem(varNode->lv_Value, varNode->lv_Len);
623 Remove((struct Node *)varNode);
624 FreeVec(varNode);
628 BPTR internal_CopyPath(BPTR boldpath, struct DosLibrary * DOSBase)
630 BPTR *nextpath, path, *newpath, *oldpath;
632 oldpath = BADDR(boldpath);
634 for (newpath = &path; oldpath != NULL; newpath = nextpath, oldpath = BADDR(oldpath[0])) {
635 /* NOTE: This memory allocation *must* match that which is
636 * done in C:Path!!!!
638 nextpath = AllocVec(2*sizeof(BPTR), MEMF_CLEAR);
639 if (nextpath == NULL)
640 break;
642 *newpath = MKBADDR(nextpath);
643 nextpath[1] = DupLock(oldpath[1]);
644 if (nextpath[1] == BNULL)
645 break;
648 *newpath = BNULL;
650 return path;
653 void internal_ChildWait(struct Task *task, struct DosLibrary * DOSBase)
655 while (((struct Process *)task)->pr_Flags & PRF_WAITINGFORCHILD)
656 Wait(SIGF_SINGLE);
660 void internal_ChildFree(APTR tid, struct DosLibrary * DOSBase)
662 struct Task *task = (struct Task *)tid;
663 struct Process *parent = (struct Process *)(GetETask(task)->et_Parent);
665 D(bug("Awakening the parent task %p (called %s)\n", parent, parent->pr_Task.tc_Node.ln_Name));
667 parent->pr_Flags &= ~PRF_WAITINGFORCHILD;
668 Signal(&parent->pr_Task, SIGF_SINGLE);
672 BOOL copyVars(struct Process *fromProcess, struct Process *toProcess, struct DosLibrary * DOSBase)
674 /* We must have variables to copy... */
675 if (__is_process(fromProcess))
677 struct LocalVar *varNode;
678 struct LocalVar *newVar;
680 /* We use the same strategy as in the ***Var() functions */
681 ForeachNode(&fromProcess->pr_LocalVars, varNode)
683 LONG copyLength = strlen(varNode->lv_Node.ln_Name) + 1 +
684 sizeof(struct LocalVar);
686 newVar = (struct LocalVar *)AllocVec(copyLength,
687 MEMF_PUBLIC | MEMF_CLEAR);
688 if (newVar == NULL)
689 return FALSE;
691 CopyMem(varNode, newVar, copyLength);
692 newVar->lv_Node.ln_Name = (char *)newVar +
693 sizeof(struct LocalVar);
694 D(bug("Variable with name %s copied.\n",
695 newVar->lv_Node.ln_Name));
697 if (varNode->lv_Len)
699 newVar->lv_Value = AllocMem(varNode->lv_Len, MEMF_PUBLIC);
701 if (newVar->lv_Value == NULL)
703 /* Free variable node before shutting down */
704 FreeVec(newVar);
706 return FALSE;
709 CopyMem(varNode->lv_Value, newVar->lv_Value, varNode->lv_Len);
712 AddTail((struct List *)&toProcess->pr_LocalVars,
713 (struct Node *)newVar);
717 return TRUE;
720 static void DosEntry(void)
722 struct Process *me = (struct Process *)FindTask(NULL);
723 LONG result;
724 ULONG argSize = me->pr_Arguments ? strlen(me->pr_Arguments) : 0;
725 APTR DOSBase;
726 APTR initialPC;
727 BPTR *segArray;
728 BPTR cis, cos, ces;
730 /* Save away our current streams */
731 cis = me->pr_CIS;
732 cos = me->pr_COS;
733 ces = me->pr_CES;
735 /* me->pr_Result2 contains our real entry point
737 initialPC = (APTR)me->pr_Result2;
738 me->pr_Result2 = 0;
740 D(bug("[DosEntry %p] is %synchronous\n", me, (me->pr_Flags & PRF_SYNCHRONOUS) ? "S" :"As"));
742 segArray = BADDR(me->pr_SegList);
743 if (initialPC == NULL)
744 initialPC = BADDR(segArray[3]) + sizeof(BPTR);
746 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));
748 /* Call entry point of our process, remembering stack in its pr_ReturnAddr */
749 result = CallEntry(me->pr_Arguments, argSize, initialPC, me);
751 /* Call user defined exit function before shutting down. */
752 if (me->pr_ExitCode != NULL)
755 The Ralph Babel's guru book says that pr_ExitCode
756 is passed the process return code in D0 and pr_ExitData in D1,
757 but the Matt Dillon's DICE C implementation of vfork shows that
758 those parameters are passed also on the stack.
760 #ifdef __mc68000
761 asm volatile (
762 "move.l %0, %%d0\n"
763 "move.l %1, %%d1\n"
764 "move.l %2, %%a0\n"
765 "move.l %%d0, %%sp@-\n"
766 "move.l %%d1, %%sp@-\n"
767 "jsr (%%a0)\n"
768 "addq.l #8, %%sp\n"
769 : /* No return values */
770 : "g" (result), "g" (me->pr_ExitData), "g" (me->pr_ExitCode)
771 : "d0", "d1", "a0", "a1"
773 #else
775 The AROS macros for functions with register parameters don't
776 support both register and stack parameters at once, so we use
777 the stack only on non-m68k. This oughta be fixed somehow.
779 me->pr_ExitCode(result, me->pr_ExitData);
780 #endif
783 /* Get our own private DOSBase. We'll need it for our
784 * cleanup routines.
786 * We don't want to use the parent's DOSBase, since they
787 * may have closed their handle long ago.
789 * With the current DOSBase implementation, this isn't a
790 * big deal, but if DOSBase moved to a per-opener library
791 * in the future, this would be a very subtle issue, so
792 * we're going to plan ahead and do it right.
794 DOSBase = TaggedOpenLibrary(TAGGEDOPEN_DOS);
795 if (DOSBase == NULL) {
796 D(bug("[DosEntry %p] Can't open DOS library\n", me));
797 Alert(AT_DeadEnd | AG_OpenLib | AO_DOSLib);
800 D(bug("Deleting local variables\n"));
802 /* Clean up */
803 freeLocalVars(me, DOSBase);
805 D(bug("Closing input stream\n"));
807 if (me->pr_Flags & PRF_CLOSEINPUT)
809 Close(cis);
812 D(bug("Closing output stream\n"));
814 if (me->pr_Flags & PRF_CLOSEOUTPUT)
816 Close(cos);
819 D(bug("Closing error stream\n"));
821 if (me->pr_Flags & PRF_CLOSEERROR)
823 Close(ces);
826 D(bug("Freeing arguments\n"));
828 if (me->pr_Flags & PRF_FREEARGS)
830 FreeVec(me->pr_Arguments);
833 D(bug("Unloading segment\n"));
835 if (me->pr_Flags & PRF_FREESEGLIST)
837 BPTR *segarray = BADDR(me->pr_SegList);
839 if (segarray && segarray[3])
840 UnLoadSeg(segarray[3]);
843 FreeVec(BADDR(me->pr_SegList));
845 if (me->pr_GlobVec && me->pr_GlobVec != ((struct DosLibrary *)DOSBase)->dl_GV) {
846 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));
847 D(Alert(AT_DeadEnd | AN_FreeVec));
850 D(bug("Unlocking current dir\n"));
852 if (me->pr_Flags & PRF_FREECURRDIR)
854 UnLock(me->pr_CurrentDir);
857 D(bug("Unlocking home dir\n"));
858 UnLock(me->pr_HomeDir);
860 D(bug("Closing cli_StandardError\n"));
862 if (me->pr_Flags & PRF_CLOSECLIERROR)
864 struct CommandLineInterface *cli = (struct CommandLineInterface *)(BADDR(me->pr_CLI));
865 Close(cli->cli_StandardError); /* See newcliproc.c */
868 D(bug("Freeing cli structure\n"));
870 if (me->pr_Flags & PRF_FREECLI)
872 FreeDosObject(DOS_CLI, BADDR(me->pr_CLI));
873 removefromrootnode(me, DOSBase);
874 me->pr_CLI = BNULL;
877 /* Synchronous completion must be before
878 * PRF_NOTIFYONDEATH, in case both were
879 * enabled.
881 if (me->pr_Flags & PRF_SYNCHRONOUS) {
882 D(bug("Calling ChildFree()\n"));
883 /* ChildFree signals the parent */
884 internal_ChildFree(me, DOSBase);
887 /* Notify of the child's death.
889 if (me->pr_Flags & PRF_NOTIFYONDEATH)
891 Signal(GetETask(me)->et_Parent, SIGF_CHILD);
894 CloseLibrary((APTR)DOSBase);
898 * This is a version of Open("NIL:") that works inside a task.
900 static BPTR OpenNIL(struct DosLibrary *DOSBase)
902 struct FileHandle *fh;
904 if ((fh = (struct FileHandle *)AllocDosObject(DOS_FILEHANDLE,NULL))) {
905 return (BPTR)handleNIL(ACTION_FINDINPUT, (SIPTR)MKBADDR(fh), (SIPTR)NULL, (SIPTR)NULL);
908 return BNULL;