2 Copyright © 2008-2009, The AROS Development Team. All rights reserved.
6 #include <proto/exec.h>
9 #include <exec/tasks.h>
11 #include <dos/filesystem.h>
14 #include <sys/types.h>
23 #include "__arosc_privdata.h"
30 #include <aros/debug.h>
31 #include <aros/startup.h>
33 /* The following functions are used to update the childs and parents privdata
34 for the parent pretending to be running as child and for the child to take over. It is called
35 in the following sequence:
36 parent_enterpretendchild() is called in vfork so the parent pretends to be running as child
37 child_takeover() is called by child if exec*() so it can continue from the parent state
38 parent_leavepretendchild() is called by parent to switch back to be running as parent
40 static void parent_enterpretendchild(struct vfork_data
*udata
);
41 static void child_takeover(struct vfork_data
*udata
);
42 static void parent_leavepretendchild(struct vfork_data
*udata
);
46 D(bug("launcher: Entered child launcher\n"));
48 struct Task
*this = FindTask(NULL
);
49 struct vfork_data
*udata
= this->tc_UserData
;
51 struct Library
*aroscbase
= NULL
;
53 GetIntETask(this)->iet_startup
= GetETask(this)->et_Result2
= AllocVec(sizeof(struct arosc_startup
), MEMF_ANY
| MEMF_CLEAR
);
55 /* Allocate signal for parent->child communication */
56 child_signal
= udata
->child_signal
= AllocSignal(-1);
57 D(bug("launcher: Allocated child signal: %d\n", udata
->child_signal
));
58 if(udata
->child_signal
== -1)
61 udata
->child_errno
= ENOMEM
;
62 Signal(udata
->parent
, 1 << udata
->parent_signal
);
66 if(__register_init_fdarray(udata
->ppriv
))
67 aroscbase
= OpenLibrary((STRPTR
) "arosc.library", 0);
70 FreeSignal(child_signal
);
71 udata
->child_errno
= ENOMEM
;
72 Signal(udata
->parent
, 1 << udata
->parent_signal
);
76 udata
->cpriv
= __get_arosc_privdata();
77 udata
->cpriv
->acpd_parent_does_upath
= udata
->ppriv
->acpd_doupath
;
78 udata
->cpriv
->acpd_flags
|= DO_NOT_CLONE_ENV_VARS
;
80 if(setjmp(__aros_startup_jmp_buf
) == 0)
82 /* Setup complete, signal parent */
83 D(bug("launcher: Signaling parent that we finished setup\n"));
84 Signal(udata
->parent
, 1 << udata
->parent_signal
);
86 D(bug("launcher: Child waiting for exec or exit\n"));
87 Wait(1 << udata
->child_signal
);
89 if(udata
->child_executed
)
93 D(bug("launcher: child executed\n"));
95 child_takeover(udata
);
97 /* Filenames passed from parent obey parent's __doupath */
98 __doupath
= udata
->cpriv
->acpd_parent_does_upath
;
99 D(bug("launcher: __doupath == %d for __exec_prepare()\n", __doupath
));
101 exec_id
= udata
->exec_id
= __exec_prepare(
102 udata
->exec_filename
,
108 udata
->child_errno
= errno
;
110 /* Clear __doupath again, command will set it if wanted */
113 D(bug("launcher: informing parent that we have run __exec_prepare\n"));
114 /* Inform parent that we have run __exec_prepare */
115 Signal(udata
->parent
, 1 << udata
->parent_signal
);
117 /* Wait 'till __exec_do() is called on parent process */
118 D(bug("launcher: Waiting parent to get the result\n"));
119 Wait(1 << udata
->child_signal
);
121 D(bug("launcher: informing parent that we won't use udata anymore\n"));
122 /* Inform parent that we won't use udata anymore */
123 Signal(udata
->parent
, 1 << udata
->parent_signal
);
127 D(bug("launcher: executing command\n"));
130 assert(0); /* Should not be reached */
134 D(bug("launcher: exit because execve returned with an error\n"));
140 D(bug("launcher: informing parent that we won't use udata anymore\n"));
141 /* Inform parent that we won't use udata anymore */
142 Signal(udata
->parent
, 1 << udata
->parent_signal
);
147 D(bug("launcher: freeing child_signal\n"));
148 FreeSignal(child_signal
);
151 CloseLibrary(aroscbase
);
156 pid_t
__vfork(jmp_buf env
)
158 struct Task
*this = FindTask(NULL
);
159 struct vfork_data
*udata
= AllocMem(sizeof(struct vfork_data
), MEMF_ANY
| MEMF_CLEAR
);
165 D(bug("__vfork: allocated udata %p\n", udata
));
166 bcopy(env
, &udata
->vfork_jump
, sizeof(jmp_buf));
168 struct TagItem tags
[] =
170 { NP_Entry
, (IPTR
) launcher
},
171 { NP_CloseInput
, (IPTR
) FALSE
},
172 { NP_CloseOutput
, (IPTR
) FALSE
},
173 { NP_CloseError
, (IPTR
) FALSE
},
174 { NP_Cli
, (IPTR
) TRUE
},
175 { NP_Name
, (IPTR
) "vfork()" },
176 { NP_UserData
, (IPTR
) udata
},
177 { NP_NotifyOnDeath
, (IPTR
) TRUE
},
181 udata
->parent
= this;
183 struct arosc_privdata
*ppriv
= __get_arosc_privdata();
185 D(bug("__vfork: ppriv = %x\n", ppriv
));
187 udata
->ppriv
= ppriv
;
189 /* Store parent's vfork_data to restore it later */
190 udata
->prev
= __get_arosc_privdata()->acpd_vfork_data
;
191 D(bug("__vfork: Saved old parent's vfork_data: %p\n", udata
->prev
));
193 D(bug("__vfork: backuping startup buffer\n"));
194 /* Backup startup buffer */
195 CopyMem(&__aros_startup_jmp_buf
, &udata
->startup_jmp_buf
, sizeof(jmp_buf));
197 D(bug("__vfork: Allocating parent signal\n"));
198 /* Allocate signal for child->parent communication */
199 udata
->parent_signal
= AllocSignal(-1);
200 if(udata
->parent_signal
== -1)
202 /* Couldn't allocate the signal, return -1 */
203 FreeMem(udata
, sizeof(struct vfork_data
));
205 longjmp(udata
->vfork_jump
, -1);
208 D(bug("__vfork: Creating child\n"));
209 udata
->child
= (struct Task
*) CreateNewProc(tags
);
211 if(udata
->child
== NULL
)
213 /* Something went wrong, return -1 */
214 FreeMem(udata
, sizeof(struct vfork_data
));
215 errno
= ENOMEM
; /* Most likely */
218 D(bug("__vfork: Child created %p, waiting to finish setup\n", udata
->child
));
219 udata
->child_id
= GetETaskID(udata
->child
);
220 D(bug("__vfork: Got unique child id: %d\n", udata
->child_id
));
222 /* Wait for child to finish setup */
223 Wait(1 << udata
->parent_signal
);
225 if(udata
->child_errno
)
227 /* An error occured during child setup */
228 errno
= udata
->child_errno
;
232 D(bug("__vfork: Setting jmp_buf at %p in %p\n", __aros_startup
, &__aros_startup_jmp_buf
));
233 if(setjmp(__aros_startup_jmp_buf
))
235 D(bug("__vfork: child exited\n or executed\n"));
237 /* Reinitialize variables as they may have been overwritten during setjmp */
238 ppriv
= __get_arosc_privdata();
239 udata
= ppriv
->acpd_vfork_data
;
241 D(bug("__vfork: ppriv = %x\n", ppriv
));
243 if(!udata
->child_executed
)
245 D(bug("__vfork: not executed\n"));
246 ((struct arosc_startup
*) GetIntETask(udata
->child
)->iet_startup
)->as_startup_error
= __aros_startup_error
;
247 D(bug("__vfork: Signaling child\n"));
248 Signal(udata
->child
, 1 << udata
->child_signal
);
251 D(bug("__vfork: Waiting for child to finish using udata\n"));
252 /* Wait for child to finish using udata */
253 Wait(1 << udata
->parent_signal
);
255 D(bug("__vfork: fflushing\n"));
258 D(bug("__vfork: restoring startup buffer\n"));
259 /* Restore parent startup buffer */
260 CopyMem(&udata
->startup_jmp_buf
, &__aros_startup_jmp_buf
, sizeof(jmp_buf));
262 D(bug("__vfork: freeing parent signal\n"));
263 FreeSignal(udata
->parent_signal
);
265 errno
= udata
->child_errno
;
267 D(bug("__vfork: Remembering jmp_buf\n"));
269 bcopy(&udata
->vfork_jump
, env
, sizeof(jmp_buf));
271 parent_leavepretendchild(udata
);
273 D(bug("__vfork: freeing udata\n"));
274 FreeMem(udata
, sizeof(struct vfork_data
));
276 D(bug("__vfork: Child(%d) jumping to jmp_buf %p\n", udata
->child_id
, &env
));
277 D(bug("__vfork: ip: %p, stack: %p\n", env
->retaddr
, env
->regs
[_JMPLEN
- 1]));
278 vfork_longjmp(env
, udata
->child_id
);
279 assert(0); /* not reached */
283 parent_enterpretendchild(udata
);
285 D(bug("__vfork: Jumping to jmp_buf %p\n", &udata
->vfork_jump
));
286 D(bug("__vfork: ip: %p, stack: %p\n", udata
->vfork_jump
[0].retaddr
, udata
->vfork_jump
[0].regs
[_JMPLEN
- 1]));
287 vfork_longjmp(udata
->vfork_jump
, 0);
288 assert(0); /* not reached */
293 static void parent_enterpretendchild(struct vfork_data
*udata
)
295 D(bug("parent_enterpretendchild(%x): entered\n", udata
));
297 udata
->ppriv
->acpd_vfork_data
= udata
;
299 /* Remember and switch malloc mempool */
300 udata
->parent_mempool
= udata
->ppriv
->acpd_mempool
;
301 udata
->ppriv
->acpd_mempool
= udata
->cpriv
->acpd_mempool
;
303 /* Remember and switch fd descriptor table */
304 udata
->parent_acpd_fd_mempool
= udata
->ppriv
->acpd_fd_mempool
;
305 udata
->parent_acpd_numslots
= udata
->ppriv
->acpd_numslots
;
306 udata
->parent_acpd_fd_array
= udata
->ppriv
->acpd_fd_array
;
307 udata
->ppriv
->acpd_fd_mempool
= udata
->cpriv
->acpd_fd_mempool
;
308 udata
->ppriv
->acpd_numslots
= udata
->cpriv
->acpd_numslots
;
309 udata
->ppriv
->acpd_fd_array
= udata
->cpriv
->acpd_fd_array
;
311 /* Remember and switch chdir fields */
312 udata
->parent_cd_changed
= __cd_changed
;
313 udata
->parent_cd_lock
= __cd_lock
;
314 __cd_changed
= udata
->cpriv
->acpd_cd_changed
;
315 __cd_lock
= udata
->cpriv
->acpd_cd_lock
;
316 udata
->parent_curdir
= CurrentDir(((struct Process
*)udata
->child
)->pr_CurrentDir
);
318 /* Pretend to be running as the child created by vfork */
319 udata
->ppriv
->acpd_flags
|= PRETEND_CHILD
;
321 D(bug("parent_enterpretendchild: leaving\n"));
324 static void child_takeover(struct vfork_data
*udata
)
326 D(bug("child_takeover(%x): entered\n", udata
));
328 /* Set current dir to parent's current dir */
329 __cd_changed
= udata
->ppriv
->acpd_cd_changed
;
330 __cd_lock
= udata
->ppriv
->acpd_cd_lock
;
331 CurrentDir(((struct Process
*)udata
->parent
)->pr_CurrentDir
);
333 D(bug("child_takeover(): leaving\n"));
336 static void parent_leavepretendchild(struct vfork_data
*udata
)
338 D(bug("parent_leavepretendchild(%x): entered\n", udata
));
340 /* Restore parent's malloc mempool */
341 udata
->ppriv
->acpd_mempool
= udata
->parent_mempool
;
343 /* Restore parent's old fd_array */
344 udata
->ppriv
->acpd_fd_mempool
= udata
->parent_acpd_fd_mempool
;
345 udata
->ppriv
->acpd_numslots
= udata
->parent_acpd_numslots
;
346 udata
->ppriv
->acpd_fd_array
= udata
->parent_acpd_fd_array
;
348 /* Switch to currentdir from before vfork() call */
349 __cd_changed
= udata
->parent_cd_changed
;
350 __cd_lock
= udata
->parent_cd_lock
;
351 CurrentDir(udata
->parent_curdir
);
353 /* Switch to previous vfork_data */
354 udata
->ppriv
->acpd_vfork_data
= udata
->prev
;
355 if(udata
->prev
== NULL
)
356 udata
->ppriv
->acpd_flags
&= ~PRETEND_CHILD
;
358 D(bug("parent_leavepretendchild: leaving\n"));