Fixed UHCI port bits for big endian machines.
[cake.git] / compiler / clib / __vfork.c
blob4a27f980f1ba43c450e35248dd7f9ae2a66ac597
1 /*
2 Copyright © 2008-2009, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <proto/dos.h>
8 #include <exec/exec.h>
9 #include <exec/tasks.h>
10 #include <dos/dos.h>
11 #include <dos/filesystem.h>
12 #include <aros/cpu.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <setjmp.h>
17 #include <errno.h>
18 #include <assert.h>
19 #include <stdlib.h>
20 #include <stdio.h>
22 #include "etask.h"
23 #include "__arosc_privdata.h"
24 #include "__open.h"
25 #include "__vfork.h"
26 #include "__exec.h"
28 #define DEBUG 0
30 #include <aros/debug.h>
31 #include <aros/startup.h>
33 BPTR DupFHFromfd(int fd, ULONG mode);
34 void vfork_longjmp (jmp_buf env, int val);
35 LONG exec_command(BPTR seglist, char *taskname, char *args, ULONG stacksize);
37 LONG launcher()
39 D(bug("launcher: Entered child launcher\n"));
41 struct Task *this = FindTask(NULL);
42 struct vfork_data *udata = this->tc_UserData;
43 BYTE child_signal;
44 struct Library *aroscbase = NULL;
46 GetIntETask(this)->iet_startup = GetETask(this)->et_Result2 = AllocVec(sizeof(struct aros_startup), MEMF_ANY | MEMF_CLEAR);
48 /* Allocate signal for parent->child communication */
49 child_signal = udata->child_signal = AllocSignal(-1);
50 D(bug("launcher: Allocated child signal: %d\n", udata->child_signal));
51 if(udata->child_signal == -1)
53 /* Lie */
54 udata->child_errno = ENOMEM;
55 Signal(udata->parent, 1 << udata->parent_signal);
56 return -1;
59 if(__register_init_fdarray(udata->ppriv->acpd_fd_array, udata->ppriv->acpd_numslots))
60 aroscbase = OpenLibrary((STRPTR) "arosc.library", 0);
61 if(!aroscbase)
63 FreeSignal(child_signal);
64 udata->child_errno = ENOMEM;
65 Signal(udata->parent, 1 << udata->parent_signal);
66 return -1;
69 udata->cpriv = __get_arosc_privdata();
70 udata->cpriv->acpd_parent_does_upath = udata->ppriv->acpd_doupath;
71 udata->cpriv->acpd_flags |= DO_NOT_CLONE_ENV_VARS;
73 if(setjmp(__aros_startup_jmp_buf) == 0)
75 /* Setup complete, signal parent */
76 D(bug("launcher: Signaling parent that we finished setup\n"));
77 Signal(udata->parent, 1 << udata->parent_signal);
79 D(bug("launcher: Child waiting for exec or exit\n"));
80 Wait(1 << udata->child_signal);
82 if(udata->child_executed)
84 APTR exec_id;
85 BPTR dir;
87 D(bug("launcher: child executed\n"));
89 /* Set current dir to parent's current dir */
90 dir = DupLock(((struct Process *)udata->parent)->pr_CurrentDir);
91 UnLock(CurrentDir(dir));
92 /* Don't mind updating aroscbase->acb_startup_cd_changed as we will
93 exit from process after __exec_do has finished */
95 /* Filenames passed from parent obey parent's __doupath */
96 __doupath = udata->cpriv->acpd_parent_does_upath;
97 D(bug("launcher: __doupath == %d for __exec_prepare()\n", __doupath));
99 exec_id = udata->exec_id = __exec_prepare(
100 udata->exec_filename,
101 udata->exec_searchpath,
102 udata->exec_argv,
103 udata->exec_envp
106 udata->child_errno = errno;
108 /* Clear __doupath again, command will set it if wanted */
109 __doupath = 0;
111 D(bug("launcher: informing parent that we have run __exec_prepare\n"));
112 /* Inform parent that we have run __exec_prepare */
113 Signal(udata->parent, 1 << udata->parent_signal);
115 /* Wait 'till __exec_do() is called on parent process */
116 D(bug("launcher: Waiting parent to get the result\n"));
117 Wait(1 << udata->child_signal);
119 D(bug("launcher: informing parent that we won't use udata anymore\n"));
120 /* Inform parent that we won't use udata anymore */
121 Signal(udata->parent, 1 << udata->parent_signal);
123 if (exec_id)
125 D(bug("launcher: executing command\n"));
126 __exec_do(exec_id);
128 assert(0); /* Should not be reached */
130 else
132 D(bug("launcher: exit because execve returned with an error\n"));
133 _exit(0);
136 else
138 D(bug("launcher: informing parent that we won't use udata anymore\n"));
139 /* Inform parent that we won't use udata anymore */
140 Signal(udata->parent, 1 << udata->parent_signal);
143 else
145 D(bug("launcher: freeing child_signal\n"));
146 FreeSignal(child_signal);
147 CloseLibrary(aroscbase);
150 return 0;
153 void FreeAndJump(struct vfork_data *udata)
155 D(bug("FreeAndJump(udata = %p)\n", udata));
156 jmp_buf env;
157 ULONG child_id = udata->child_id;
158 D(bug("FreeAndJump: Child ID=%d\n", child_id));
159 bcopy(&udata->vfork_jump, env, sizeof(jmp_buf));
160 D(bug("FreeAndJump: Restoring old vfork_data: %p\n", udata->prev));
161 __get_arosc_privdata()->acpd_vfork_data = udata->prev;
162 if(udata->prev == NULL)
163 __get_arosc_privdata()->acpd_flags &= ~PRETEND_CHILD;
164 D(bug("FreeAndJump: freeing udata\n"));
165 FreeMem(udata, sizeof(struct vfork_data));
166 D(bug("FreeAndJump: Jumping to jmp_buf %p\n", &env));
167 D(bug("FreeAndJump: ip: %p, stack: %p\n", env->retaddr, env->regs[_JMPLEN - 1]));
168 vfork_longjmp(env, child_id);
171 pid_t __vfork(jmp_buf env)
173 struct Task *this = FindTask(NULL);
174 struct vfork_data *udata = AllocMem(sizeof(struct vfork_data), MEMF_ANY | MEMF_CLEAR);
175 if(udata == NULL)
177 errno = ENOMEM;
178 longjmp(env, -1);
180 D(bug("__vfork: allocated udata %p\n", udata));
181 bcopy(env, &udata->vfork_jump, sizeof(jmp_buf));
183 struct TagItem tags[] =
185 { NP_Entry, (IPTR) launcher },
186 { NP_CloseInput, (IPTR) FALSE },
187 { NP_CloseOutput, (IPTR) FALSE },
188 { NP_CloseError, (IPTR) FALSE },
189 { NP_Cli, (IPTR) TRUE },
190 { NP_Name, (IPTR) "vfork()" },
191 { NP_UserData, (IPTR) udata },
192 { NP_NotifyOnDeath, (IPTR) TRUE },
193 { TAG_DONE, 0 }
196 udata->parent = this;
198 struct arosc_privdata *ppriv = __get_arosc_privdata();
199 udata->ppriv = ppriv;
201 /* Store parent's vfork_data to restore it later */
202 udata->prev = __get_arosc_privdata()->acpd_vfork_data;
203 D(bug("__vfork: Saved old parent's vfork_data: %p\n", udata->prev));
205 D(bug("__vfork: backuping startup buffer\n"));
206 /* Backup startup buffer */
207 CopyMem(&__aros_startup_jmp_buf, &udata->startup_jmp_buf, sizeof(jmp_buf));
209 D(bug("__vfork: Allocating parent signal\n"));
210 /* Allocate signal for child->parent communication */
211 udata->parent_signal = AllocSignal(-1);
212 if(udata->parent_signal == -1)
214 /* Couldn't allocate the signal, return -1 */
215 FreeMem(udata, sizeof(struct vfork_data));
216 errno = ENOMEM;
217 longjmp(udata->vfork_jump, -1);
220 D(bug("__vfork: Creating child\n"));
221 udata->child = (struct Task*) CreateNewProc(tags);
223 if(udata->child == NULL)
225 /* Something went wrong, return -1 */
226 FreeMem(udata, sizeof(struct vfork_data));
227 errno = ENOMEM; /* Most likely */
228 longjmp(env, -1);
230 D(bug("__vfork: Child created %p, waiting to finish setup\n", udata->child));
231 udata->child_id = GetETaskID(udata->child);
232 D(bug("__vfork: Got unique child id: %d\n", udata->child_id));
234 /* Wait for child to finish setup */
235 Wait(1 << udata->parent_signal);
237 if(udata->child_errno)
239 /* An error occured during child setup */
240 errno = udata->child_errno;
241 longjmp(env, -1);
244 D(bug("__vfork: Setting jmp_buf at %p in %p\n", __aros_startup, &__aros_startup_jmp_buf));
245 if(setjmp(__aros_startup_jmp_buf))
247 D(bug("__vfork: child exited\n or executed\n"));
249 if(!GETUDATA->child_executed)
251 D(bug("__vfork: not executed\n"));
252 ((struct aros_startup*) GetIntETask(GETUDATA->child)->iet_startup)->as_startup_error = __aros_startup_error;
253 D(bug("__vfork: Signaling child\n"));
254 Signal(GETUDATA->child, 1 << GETUDATA->child_signal);
257 D(bug("__vfork: Waiting for child to finish using udata\n"));
258 /* Wait for child to finish using GETUDATA */
259 Wait(1 << GETUDATA->parent_signal);
261 D(bug("__vfork: fflushing\n"));
262 fflush(NULL);
264 D(bug("__vfork: restoring old fd_array\n"));
265 /* Restore parent's old fd_array */
266 ((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_fd_mempool = GETUDATA->parent_acpd_fd_mempool;
267 ((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_numslots = GETUDATA->parent_acpd_numslots;
268 ((struct arosc_privdata *) GetIntETask(GETUDATA->parent)->iet_acpd)->acpd_fd_array = GETUDATA->parent_acpd_fd_array;
270 D(bug("__vfork: restoring startup buffer\n"));
271 /* Restore parent startup buffer */
272 CopyMem(&GETUDATA->startup_jmp_buf, &__aros_startup_jmp_buf, sizeof(jmp_buf));
274 D(bug("__vfork: freeing parent signal\n"));
275 FreeSignal(GETUDATA->parent_signal);
277 errno = GETUDATA->child_errno;
279 FreeAndJump(GETUDATA);
280 assert(0); /* not reached */
281 return (pid_t) 1;
284 /* Remember parent fd descriptor table */
285 udata->parent_acpd_fd_mempool = ppriv->acpd_fd_mempool;
286 udata->parent_acpd_numslots = ppriv->acpd_numslots;
287 udata->parent_acpd_fd_array = ppriv->acpd_fd_array;
289 /* Pretend to be running as the child created by vfork */
290 ppriv->acpd_vfork_data = udata;
291 ppriv->acpd_flags |= PRETEND_CHILD;
292 ppriv->acpd_fd_mempool = udata->cpriv->acpd_fd_mempool;
293 ppriv->acpd_numslots = udata->cpriv->acpd_numslots;
294 ppriv->acpd_fd_array = udata->cpriv->acpd_fd_array;
296 D(bug("__vfork: Jumping to jmp_buf %p\n", &udata->vfork_jump));
297 D(bug("__vfork: ip: %p, stack: %p\n", udata->vfork_jump[0].retaddr, udata->vfork_jump[0].regs[_JMPLEN - 1]));
298 vfork_longjmp(udata->vfork_jump, 0);
299 assert(0); /* not reached */
300 return (pid_t) 0;