2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
5 Desc: Create a new process
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
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 /*****************************************************************************
42 #include <proto/dos.h>
44 AROS_LH1(struct Process
*, CreateNewProc
,
47 AROS_LHA(const struct TagItem
*, tags
, D1
),
50 struct DosLibrary
*, DOSBase
, 83, Dos
)
53 Create a new process using the tagitem array.
56 tags - information on the new process.
59 Pointer to the new process or NULL on error.
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.
76 *****************************************************************************/
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
);
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
},
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();
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
);
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)
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))
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.
193 process
= AllocMem(sizeof(struct Process
), MEMF_PUBLIC
| MEMF_31BIT
| MEMF_CLEAR
);
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:
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
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
);
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
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
),
254 ENOMEM_IF(memlist
== NULL
);
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();
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
;
292 cli
->cli_CommandDir
= internal_CopyPath(oldpath
, DOSBase
);
298 if (defaults
[2].ti_Data
== TAGDATA_NOT_SPECIFIED
)
300 input
= OpenNIL(DOSBase
);
303 defaults
[2].ti_Data
= (IPTR
)input
;
308 if (defaults
[4].ti_Data
== TAGDATA_NOT_SPECIFIED
)
310 output
= OpenNIL(DOSBase
);
313 defaults
[4].ti_Data
= (IPTR
)output
;
318 if (defaults
[6].ti_Data
== TAGDATA_NOT_SPECIFIED
)
320 ces
= OpenNIL(DOSBase
);
323 defaults
[6].ti_Data
= (IPTR
)ces
;
328 if (defaults
[8].ti_Data
== TAGDATA_NOT_SPECIFIED
)
330 if (__is_process(me
) && me
->pr_CurrentDir
)
332 curdir
= Lock("", SHARED_LOCK
);
335 defaults
[8].ti_Data
= (IPTR
)curdir
;
339 defaults
[8].ti_Data
= 0;
345 if (defaults
[21].ti_Data
== TAGDATA_NOT_SPECIFIED
)
347 defaults
[21].ti_Data
= 0;
349 if (__is_process(me
))
353 homedir
= DupLock(me
->pr_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
;
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 */
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.
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
)
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);
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
);
549 D(bug("[createnewproc] Failed to create process\n"));
553 FreeDosObject(DOS_CLI
, cli
);
556 if (homedir
!= BNULL
)
585 FreeMem(memlist
, sizeof(struct MemList
) + 2*sizeof(struct MemEntry
));
590 FreeMem(name
, namesize
);
595 FreeMem(stack
, process
->pr_StackSize
);
600 FreeMem(process
, sizeof(struct Process
));
607 if (defaults
[19].ti_Data
)
608 SetSignal(SIGF_SINGLE
, old_sig
);
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
,
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
);
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
641 nextpath
= AllocVec(2*sizeof(BPTR
), MEMF_CLEAR
);
642 if (nextpath
== NULL
)
645 *newpath
= MKBADDR(nextpath
);
646 nextpath
[1] = DupLock(oldpath
[1]);
647 if (nextpath
[1] == BNULL
)
656 void internal_ChildWait(struct Task
*task
, struct DosLibrary
* DOSBase
)
658 while (((struct Process
*)task
)->pr_Flags
& PRF_WAITINGFORCHILD
)
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
);
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
));
702 newVar
->lv_Value
= AllocMem(varNode
->lv_Len
, MEMF_PUBLIC
);
704 if (newVar
->lv_Value
== NULL
)
706 /* Free variable node before shutting down */
712 CopyMem(varNode
->lv_Value
, newVar
->lv_Value
, varNode
->lv_Len
);
715 AddTail((struct List
*)&toProcess
->pr_LocalVars
,
716 (struct Node
*)newVar
);
723 static void DosEntry(void)
725 struct Process
*me
= (struct Process
*)FindTask(NULL
);
727 ULONG argSize
= me
->pr_Arguments
? strlen(me
->pr_Arguments
) : 0;
733 /* Save away our current streams */
738 /* me->pr_Result2 contains our real entry point
740 initialPC
= (APTR
)me
->pr_Result2
;
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.
768 "move.l %%d0, %%sp@-\n"
769 "move.l %%d1, %%sp@-\n"
772 : /* No return values */
773 : "g" (result
), "g" (me
->pr_ExitData
), "g" (me
->pr_ExitCode
)
774 : "d0", "d1", "a0", "a1"
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
);
786 /* Get our own private DOSBase. We'll need it for our
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"));
806 freeLocalVars(me
, DOSBase
);
808 D(bug("Closing input stream\n"));
810 if (me
->pr_Flags
& PRF_CLOSEINPUT
)
815 D(bug("Closing output stream\n"));
817 if (me
->pr_Flags
& PRF_CLOSEOUTPUT
)
822 D(bug("Closing error stream\n"));
824 if (me
->pr_Flags
& PRF_CLOSEERROR
)
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
);
880 /* Synchronous completion must be before
881 * PRF_NOTIFYONDEATH, in case both were
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
);