2 Copyright © 1995-2013, 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(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
, (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
},
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
;
148 ApplyTagChanges(defaults
, (struct TagItem
*)tags
);
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)
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))
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.
190 process
= AllocMem(sizeof(struct Process
), MEMF_PUBLIC
| MEMF_31BIT
| MEMF_CLEAR
);
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:
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
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
);
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
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
),
251 ENOMEM_IF(memlist
== NULL
);
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();
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
;
289 cli
->cli_CommandDir
= internal_CopyPath(oldpath
, DOSBase
);
295 if (defaults
[2].ti_Data
== TAGDATA_NOT_SPECIFIED
)
297 input
= OpenNIL(DOSBase
);
300 defaults
[2].ti_Data
= (IPTR
)input
;
305 if (defaults
[4].ti_Data
== TAGDATA_NOT_SPECIFIED
)
307 output
= OpenNIL(DOSBase
);
310 defaults
[4].ti_Data
= (IPTR
)output
;
315 if (defaults
[6].ti_Data
== TAGDATA_NOT_SPECIFIED
)
317 ces
= OpenNIL(DOSBase
);
320 defaults
[6].ti_Data
= (IPTR
)ces
;
325 if (defaults
[8].ti_Data
== TAGDATA_NOT_SPECIFIED
)
327 if (__is_process(me
) && me
->pr_CurrentDir
)
329 curdir
= Lock("", SHARED_LOCK
);
332 defaults
[8].ti_Data
= (IPTR
)curdir
;
336 defaults
[8].ti_Data
= 0;
342 if (defaults
[21].ti_Data
== TAGDATA_NOT_SPECIFIED
)
344 defaults
[21].ti_Data
= 0;
346 if (__is_process(me
))
350 homedir
= DupLock(me
->pr_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
;
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 */
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.
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
)
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);
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
);
546 D(bug("[createnewproc] Failed to create process\n"));
550 FreeDosObject(DOS_CLI
, cli
);
553 if (homedir
!= BNULL
)
582 FreeMem(memlist
, sizeof(struct MemList
) + 2*sizeof(struct MemEntry
));
587 FreeMem(name
, namesize
);
592 FreeMem(stack
, process
->pr_StackSize
);
597 FreeMem(process
, sizeof(struct Process
));
604 if (defaults
[19].ti_Data
)
605 SetSignal(SIGF_SINGLE
, old_sig
);
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
,
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
);
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
638 nextpath
= AllocVec(2*sizeof(BPTR
), MEMF_CLEAR
);
639 if (nextpath
== NULL
)
642 *newpath
= MKBADDR(nextpath
);
643 nextpath
[1] = DupLock(oldpath
[1]);
644 if (nextpath
[1] == BNULL
)
653 void internal_ChildWait(struct Task
*task
, struct DosLibrary
* DOSBase
)
655 while (((struct Process
*)task
)->pr_Flags
& PRF_WAITINGFORCHILD
)
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
);
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
));
699 newVar
->lv_Value
= AllocMem(varNode
->lv_Len
, MEMF_PUBLIC
);
701 if (newVar
->lv_Value
== NULL
)
703 /* Free variable node before shutting down */
709 CopyMem(varNode
->lv_Value
, newVar
->lv_Value
, varNode
->lv_Len
);
712 AddTail((struct List
*)&toProcess
->pr_LocalVars
,
713 (struct Node
*)newVar
);
720 static void DosEntry(void)
722 struct Process
*me
= (struct Process
*)FindTask(NULL
);
724 ULONG argSize
= me
->pr_Arguments
? strlen(me
->pr_Arguments
) : 0;
730 /* Save away our current streams */
735 /* me->pr_Result2 contains our real entry point
737 initialPC
= (APTR
)me
->pr_Result2
;
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.
765 "move.l %%d0, %%sp@-\n"
766 "move.l %%d1, %%sp@-\n"
769 : /* No return values */
770 : "g" (result
), "g" (me
->pr_ExitData
), "g" (me
->pr_ExitCode
)
771 : "d0", "d1", "a0", "a1"
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
);
783 /* Get our own private DOSBase. We'll need it for our
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"));
803 freeLocalVars(me
, DOSBase
);
805 D(bug("Closing input stream\n"));
807 if (me
->pr_Flags
& PRF_CLOSEINPUT
)
812 D(bug("Closing output stream\n"));
814 if (me
->pr_Flags
& PRF_CLOSEOUTPUT
)
819 D(bug("Closing error stream\n"));
821 if (me
->pr_Flags
& PRF_CLOSEERROR
)
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
);
877 /* Synchronous completion must be before
878 * PRF_NOTIFYONDEATH, in case both were
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
);