]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* fork.cc |
2 | ||
ce006ffa | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
4c8d72de | 11 | #include "winsup.h" |
1fd5e000 CF |
12 | #include <stdio.h> |
13 | #include <unistd.h> | |
14 | #include <stdlib.h> | |
1fd5e000 CF |
15 | #include <stdarg.h> |
16 | #include <errno.h> | |
6b91b8d5 | 17 | #include "security.h" |
bccd5e0d | 18 | #include "fhandler.h" |
47063f00 | 19 | #include "path.h" |
e2ebe117 | 20 | #include "dtable.h" |
9e2baf8d | 21 | #include "cygerrno.h" |
bccd5e0d CF |
22 | #include "sigproc.h" |
23 | #include "pinfo.h" | |
b0e82b74 | 24 | #include "cygheap.h" |
488c7683 | 25 | #include "child_info.h" |
f0338f54 | 26 | #define NEED_VFORK |
bccd5e0d | 27 | #include "perthread.h" |
f0338f54 CF |
28 | #include "perprocess.h" |
29 | #include "dll_init.h" | |
c7e2187a CF |
30 | #include "sync.h" |
31 | #include "cygmalloc.h" | |
1fd5e000 | 32 | |
84aeff41 | 33 | #ifdef DEBUGGING |
08b78edf CF |
34 | static int npid; |
35 | static int npid_max; | |
36 | static pid_t fork_pids[100]; | |
84aeff41 CF |
37 | #endif |
38 | ||
1fd5e000 CF |
39 | /* Timeout to wait for child to start, parent to init child, etc. */ |
40 | /* FIXME: Once things stabilize, bump up to a few minutes. */ | |
41 | #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ | |
42 | ||
43 | #define dll_data_start &_data_start__ | |
44 | #define dll_data_end &_data_end__ | |
45 | #define dll_bss_start &_bss_start__ | |
46 | #define dll_bss_end &_bss_end__ | |
47 | ||
48 | void | |
49 | per_thread::set (void *s) | |
b0e82b74 CF |
50 | { |
51 | if (s == PER_THREAD_FORK_CLEAR) | |
52 | { | |
53 | tls = TlsAlloc (); | |
54 | s = NULL; | |
55 | } | |
56 | TlsSetValue (get_tls (), s); | |
57 | } | |
1fd5e000 CF |
58 | |
59 | static void | |
60 | stack_base (child_info_fork &ch) | |
61 | { | |
62 | MEMORY_BASIC_INFORMATION m; | |
63 | memset (&m, 0, sizeof m); | |
64 | if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) | |
65 | system_printf ("couldn't get memory info, %E"); | |
66 | ||
67 | ch.stacktop = m.AllocationBase; | |
68 | ch.stackbottom = (LPBYTE) m.BaseAddress + m.RegionSize; | |
69 | ch.stacksize = (DWORD) ch.stackbottom - (DWORD) &m; | |
70 | debug_printf ("bottom %p, top %p, stack %p, size %d, reserve %d", | |
71 | ch.stackbottom, ch.stacktop, &m, ch.stacksize, | |
72 | (DWORD) ch.stackbottom - (DWORD) ch.stacktop); | |
73 | } | |
74 | ||
75 | /* Copy memory from parent to child. | |
76 | The result is a boolean indicating success. */ | |
77 | ||
78 | static int | |
79 | fork_copy (PROCESS_INFORMATION &pi, const char *what, ...) | |
80 | { | |
81 | va_list args; | |
82 | char *low; | |
83 | int pass = 0; | |
84 | ||
85 | va_start (args, what); | |
86 | ||
87 | while ((low = va_arg (args, char *))) | |
88 | { | |
89 | char *high = va_arg (args, char *); | |
ba946828 | 90 | DWORD todo = wincap.chunksize () ?: high - low; |
1fd5e000 CF |
91 | char *here; |
92 | ||
93 | for (here = low; here < high; here += todo) | |
94 | { | |
95 | DWORD done = 0; | |
96 | if (here + todo > high) | |
97 | todo = high - here; | |
98 | int res = WriteProcessMemory (pi.hProcess, here, here, todo, &done); | |
99 | debug_printf ("child handle %p, low %p, high %p, res %d", pi.hProcess, | |
100 | low, high, res); | |
101 | if (!res || todo != done) | |
102 | { | |
103 | if (!res) | |
104 | __seterrno (); | |
105 | /* If this happens then there is a bug in our fork | |
106 | implementation somewhere. */ | |
20a2c443 CF |
107 | system_printf ("%s pass %d failed, %p..%p, done %d, windows pid %u, %E", |
108 | what, pass, low, high, done, pi.dwProcessId); | |
1fd5e000 CF |
109 | goto err; |
110 | } | |
111 | } | |
112 | ||
113 | pass++; | |
114 | } | |
115 | ||
116 | debug_printf ("done"); | |
117 | return 1; | |
118 | ||
e5ba4c06 | 119 | err: |
1fd5e000 CF |
120 | TerminateProcess (pi.hProcess, 1); |
121 | set_errno (EAGAIN); | |
122 | return 0; | |
123 | } | |
124 | ||
125 | /* Wait for child to finish what it's doing and signal us. | |
126 | We don't want to wait forever here.If there's a problem somewhere | |
127 | it'll hang the entire system (since all forks are mutex'd). If we | |
128 | time out, set errno = EAGAIN and hope the app tries again. */ | |
129 | static int | |
130 | sync_with_child (PROCESS_INFORMATION &pi, HANDLE subproc_ready, | |
131 | BOOL hang_child, const char *s) | |
132 | { | |
133 | /* We also add the child process handle to the wait. If the child fails | |
134 | to initialize (eg. because of a missing dll). Then this | |
135 | handle will become signalled. This stops a *looong* timeout wait. | |
136 | */ | |
137 | HANDLE w4[2]; | |
138 | ||
ec300c99 CF |
139 | debug_printf ("waiting for child. reason: %s, hang_child %d", s, |
140 | hang_child); | |
1fd5e000 CF |
141 | w4[1] = pi.hProcess; |
142 | w4[0] = subproc_ready; | |
143 | DWORD rc = WaitForMultipleObjects (2, w4, FALSE, FORK_WAIT_TIMEOUT); | |
144 | ||
145 | if (rc == WAIT_OBJECT_0 || | |
146 | WaitForSingleObject (subproc_ready, 0) == WAIT_OBJECT_0) | |
147 | /* That's ok */; | |
148 | else if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT) | |
149 | { | |
150 | if (rc != WAIT_FAILED) | |
151 | system_printf ("WaitForMultipleObjects timed out"); | |
152 | else | |
153 | system_printf ("WaitForMultipleObjects failed, %E"); | |
154 | set_errno (EAGAIN); | |
155 | syscall_printf ("-1 = fork(), WaitForMultipleObjects failed"); | |
156 | TerminateProcess (pi.hProcess, 1); | |
157 | return 0; | |
158 | } | |
159 | else | |
160 | { | |
161 | /* Child died. Clean up and exit. */ | |
162 | DWORD errcode; | |
163 | GetExitCodeProcess (pi.hProcess, &errcode); | |
164 | /* Fix me. This is not enough. The fork should not be considered | |
165 | * to have failed if the process was essentially killed by a signal. | |
166 | */ | |
167 | if (errcode != STATUS_CONTROL_C_EXIT) | |
168 | { | |
169 | system_printf ("child %d(%p) died before initialization with status code %p", | |
170 | pi.dwProcessId, pi.hProcess, errcode); | |
171 | system_printf ("*** child state %s", s); | |
172 | #ifdef DEBUGGING | |
173 | abort (); | |
174 | #endif | |
175 | } | |
176 | set_errno (EAGAIN); | |
177 | syscall_printf ("Child died before subproc_ready signalled"); | |
178 | return 0; | |
179 | } | |
180 | ||
181 | debug_printf ("child signalled me"); | |
1fd5e000 CF |
182 | return 1; |
183 | } | |
184 | ||
185 | static int | |
9cec3d45 | 186 | resume_child (PROCESS_INFORMATION &pi, HANDLE forker_finished) |
1fd5e000 | 187 | { |
1fd5e000 | 188 | SetEvent (forker_finished); |
1ec4f618 CF |
189 | debug_printf ("signalled child"); |
190 | return 1; | |
1fd5e000 CF |
191 | } |
192 | ||
193 | /* Notify parent that it is time for the next step. | |
194 | Note that this has to be a macro since the parent may be messing with | |
195 | our stack. */ | |
1ec4f618 | 196 | static void __stdcall |
c90e1cf1 | 197 | sync_with_parent (const char *s, bool hang_self) |
1fd5e000 | 198 | { |
1ec4f618 CF |
199 | debug_printf ("signalling parent: %s", s); |
200 | /* Tell our parent we're waiting. */ | |
6ea3e429 | 201 | if (!SetEvent (fork_info->subproc_ready)) |
5e733918 | 202 | api_fatal ("fork child - SetEvent for %s failed, %E", s); |
1ec4f618 CF |
203 | if (hang_self) |
204 | { | |
6ea3e429 | 205 | HANDLE h = fork_info->forker_finished; |
1ec4f618 CF |
206 | /* Wait for the parent to fill in our stack and heap. |
207 | Don't wait forever here. If our parent dies we don't want to clog | |
208 | the system. If the wait fails, we really can't continue so exit. */ | |
209 | DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT); | |
210 | debug_printf ("awake"); | |
211 | switch (psync_rc) | |
212 | { | |
213 | case WAIT_TIMEOUT: | |
5e733918 | 214 | api_fatal ("WFSO timed out for %s", s); |
1ec4f618 CF |
215 | break; |
216 | case WAIT_FAILED: | |
217 | if (GetLastError () == ERROR_INVALID_HANDLE && | |
6ea3e429 | 218 | WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED) |
1ec4f618 | 219 | break; |
5e733918 | 220 | api_fatal ("WFSO failed for %s, fork_finished %p, %E", s, |
6ea3e429 | 221 | fork_info->forker_finished); |
1ec4f618 CF |
222 | break; |
223 | default: | |
224 | debug_printf ("no problems"); | |
225 | break; | |
226 | } | |
227 | } | |
1fd5e000 CF |
228 | } |
229 | ||
1ec4f618 CF |
230 | static int __stdcall |
231 | fork_child (HANDLE& hParent, dll *&first_dll, bool& load_dlls) | |
1fd5e000 | 232 | { |
1ec4f618 CF |
233 | debug_printf ("child is running. pid %d, ppid %d, stack here %p", |
234 | myself->pid, myself->ppid, __builtin_frame_address (0)); | |
1ec4f618 CF |
235 | |
236 | /* Restore the inheritance state as in parent | |
237 | Don't call setuid here! The flags are already set. */ | |
66c161ba | 238 | if (cygheap->user.impersonated) |
1ec4f618 | 239 | { |
66c161ba CV |
240 | debug_printf ("Impersonation of child, token: %d", cygheap->user.token); |
241 | if (cygheap->user.token == INVALID_HANDLE_VALUE) | |
1ec4f618 | 242 | RevertToSelf (); // probably not needed |
66c161ba | 243 | else if (!ImpersonateLoggedOnUser (cygheap->user.token)) |
1ec4f618 CF |
244 | system_printf ("Impersonate for forked child failed: %E"); |
245 | } | |
1fd5e000 | 246 | |
1ec4f618 | 247 | sync_with_parent ("after longjmp.", TRUE); |
a7670c1e | 248 | sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d\n", hParent, |
1ff9f4b9 | 249 | first_dll, load_dlls); |
1fd5e000 | 250 | |
1ec4f618 CF |
251 | #ifdef DEBUGGING |
252 | char c; | |
253 | if (GetEnvironmentVariable ("FORKDEBUG", &c, 1)) | |
254 | try_to_debug (); | |
255 | char buf[80]; | |
256 | /* This is useful for debugging fork problems. Use gdb to attach to | |
257 | the pid reported here. */ | |
258 | if (GetEnvironmentVariable ("CYGWIN_FORK_SLEEP", buf, sizeof (buf))) | |
259 | { | |
260 | small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ()); | |
c90e1cf1 | 261 | Sleep (atoi (buf)); |
1ec4f618 CF |
262 | } |
263 | #endif | |
1fd5e000 | 264 | |
1ec4f618 CF |
265 | /* If we've played with the stack, stacksize != 0. That means that |
266 | fork() was invoked from other than the main thread. Make sure that | |
267 | when the "main" thread exits it calls do_exit, like a normal process. | |
268 | Exit with a status code of 0. */ | |
6ea3e429 | 269 | if (fork_info->stacksize) |
1ec4f618 | 270 | { |
6ea3e429 CF |
271 | ((DWORD *)fork_info->stackbottom)[-17] = (DWORD)do_exit; |
272 | ((DWORD *)fork_info->stackbottom)[-15] = (DWORD)0; | |
1ec4f618 | 273 | } |
1fd5e000 | 274 | |
4c15b7ab ED |
275 | set_file_api_mode (current_codepage); |
276 | ||
1ec4f618 | 277 | MALLOC_CHECK; |
1fd5e000 | 278 | |
1f5ff387 | 279 | cygheap->fdtab.fixup_after_fork (hParent); |
0301bfd0 | 280 | ProtectHandleINH (hParent); |
1f5ff387 | 281 | |
1dc16fc7 | 282 | pinfo_fixup_after_fork (); |
1ec4f618 | 283 | signal_fixup_after_fork (); |
1ec4f618 CF |
284 | |
285 | MALLOC_CHECK; | |
286 | ||
464b3e80 CV |
287 | if (fixup_mmaps_after_fork (hParent)) |
288 | api_fatal ("recreate_mmaps_after_fork_failed"); | |
289 | ||
1ec4f618 CF |
290 | /* If we haven't dynamically loaded any dlls, just signal |
291 | the parent. Otherwise, load all the dlls, tell the parent | |
292 | that we're done, and wait for the parent to fill in the. | |
293 | loaded dlls' data/bss. */ | |
294 | if (!load_dlls) | |
295 | sync_with_parent ("performed fork fixup.", FALSE); | |
296 | else | |
1fd5e000 | 297 | { |
1ec4f618 CF |
298 | dlls.load_after_fork (hParent, first_dll); |
299 | sync_with_parent ("loaded dlls", TRUE); | |
1fd5e000 CF |
300 | } |
301 | ||
1ec4f618 | 302 | ForceCloseHandle (hParent); |
0301bfd0 CF |
303 | (void) ForceCloseHandle1 (fork_info->subproc_ready, subproc_ready); |
304 | (void) ForceCloseHandle1 (fork_info->forker_finished, forker_finished); | |
2eb392bd | 305 | |
f449bfef RC |
306 | if (fixup_shms_after_fork ()) |
307 | api_fatal ("recreate_shm areas after fork failed"); | |
308 | ||
1ec4f618 CF |
309 | /* Set thread local stuff to zero. Under Windows 95/98 this is sometimes |
310 | non-zero, for some reason. | |
311 | FIXME: There is a memory leak here after a fork. */ | |
312 | for (per_thread **t = threadstuff; *t; t++) | |
313 | if ((*t)->clear_on_fork ()) | |
314 | (*t)->set (); | |
1fd5e000 | 315 | |
3cb62bd6 | 316 | wait_for_sigthread (); |
f1f13795 | 317 | pthread::atforkchild (); |
166b2571 | 318 | cygbench ("fork-child"); |
1ec4f618 CF |
319 | return 0; |
320 | } | |
1fd5e000 | 321 | |
84aeff41 CF |
322 | static void |
323 | slow_pid_reuse (HANDLE h) | |
324 | { | |
0dc9dc8b | 325 | static NO_COPY HANDLE last_fork_procs[8] = {0}; |
84aeff41 CF |
326 | static NO_COPY unsigned nfork_procs = 0; |
327 | ||
5ba05cab | 328 | if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0]))) |
84aeff41 CF |
329 | nfork_procs = 0; |
330 | /* Keep a list of handles to forked processes sitting around to prevent | |
331 | Windows from reusing the same pid n times in a row. Having the same pids | |
332 | close in succesion confuses bash. Keeping a handle open will stop | |
333 | windows from reusing the same pid. */ | |
334 | if (last_fork_procs[nfork_procs]) | |
5ba05cab CF |
335 | ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
336 | if (DuplicateHandle (hMainProc, h, hMainProc, &last_fork_procs[nfork_procs], | |
84aeff41 | 337 | 0, FALSE, DUPLICATE_SAME_ACCESS)) |
5ba05cab CF |
338 | ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
339 | else | |
84aeff41 CF |
340 | { |
341 | last_fork_procs[nfork_procs] = NULL; | |
342 | system_printf ("couldn't create last_fork_proc, %E"); | |
343 | } | |
344 | nfork_procs++; | |
345 | } | |
346 | ||
1ec4f618 | 347 | static int __stdcall |
20a2c443 CF |
348 | fork_parent (HANDLE& hParent, dll *&first_dll, |
349 | bool& load_dlls, void *stack_here, child_info_fork &ch) | |
1ec4f618 CF |
350 | { |
351 | HANDLE subproc_ready, forker_finished; | |
1ec4f618 CF |
352 | DWORD rc; |
353 | PROCESS_INFORMATION pi = {0, NULL, 0, 0}; | |
1fd5e000 | 354 | |
f1f13795 | 355 | pthread::atforkprepare (); |
975d2083 | 356 | |
1ec4f618 | 357 | subproc_init (); |
1fd5e000 | 358 | |
1ec4f618 CF |
359 | int c_flags = GetPriorityClass (hMainProc) /*| |
360 | CREATE_NEW_PROCESS_GROUP*/; | |
361 | STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL}; | |
362 | ||
363 | /* If we don't have a console, then don't create a console for the | |
364 | child either. */ | |
580e99a1 CF |
365 | HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE, |
366 | FILE_SHARE_WRITE, &sec_none_nih, | |
367 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, | |
368 | NULL); | |
1ec4f618 | 369 | |
580e99a1 | 370 | if (console_handle != INVALID_HANDLE_VALUE) |
1ec4f618 CF |
371 | CloseHandle (console_handle); |
372 | else | |
373 | c_flags |= DETACHED_PROCESS; | |
1fd5e000 | 374 | |
dd4f0b23 CV |
375 | /* Some file types (currently only sockets) need extra effort in the |
376 | parent after CreateProcess and before copying the datastructures | |
377 | to the child. So we have to start the child in suspend state, | |
378 | unfortunately, to avoid a race condition. */ | |
0381fec6 | 379 | if (cygheap->fdtab.need_fixup_before ()) |
dd4f0b23 CV |
380 | c_flags |= CREATE_SUSPENDED; |
381 | ||
84aeff41 CF |
382 | /* Create an inheritable handle to pass to the child process. This will |
383 | allow the child to duplicate handles from the parent to itself. */ | |
1ec4f618 CF |
384 | hParent = NULL; |
385 | if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hParent, 0, 1, | |
386 | DUPLICATE_SAME_ACCESS)) | |
387 | { | |
388 | system_printf ("couldn't create handle to myself for child, %E"); | |
389 | return -1; | |
390 | } | |
1fd5e000 | 391 | |
1ec4f618 CF |
392 | /* Remember the address of the first loaded dll and decide |
393 | if we need to load dlls. We do this here so that this | |
394 | information will be available in the parent and, when | |
395 | the stack is copied, in the child. */ | |
396 | first_dll = dlls.start.next; | |
397 | load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; | |
1fd5e000 | 398 | |
1ec4f618 CF |
399 | /* This will help some of the confusion. */ |
400 | fflush (stdout); | |
1fd5e000 | 401 | |
1ec4f618 CF |
402 | subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL); |
403 | if (subproc_ready == NULL) | |
404 | { | |
405 | CloseHandle (hParent); | |
406 | system_printf ("unable to allocate subproc_ready event, %E"); | |
407 | return -1; | |
408 | } | |
409 | forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); | |
410 | if (forker_finished == NULL) | |
411 | { | |
412 | CloseHandle (hParent); | |
413 | CloseHandle (subproc_ready); | |
48372ea6 | 414 | system_printf ("unable to allocate forker_finished event, %E"); |
1ec4f618 CF |
415 | return -1; |
416 | } | |
1fd5e000 | 417 | |
0301bfd0 CF |
418 | ProtectHandleINH (subproc_ready); |
419 | ProtectHandleINH (forker_finished); | |
1fd5e000 | 420 | |
57013c31 | 421 | init_child_info (PROC_FORK, &ch, 1, subproc_ready); |
1fd5e000 | 422 | |
1ec4f618 | 423 | ch.forker_finished = forker_finished; |
1fd5e000 | 424 | |
1ec4f618 | 425 | stack_base (ch); |
1fd5e000 | 426 | |
1ec4f618 CF |
427 | si.cb = sizeof (STARTUPINFO); |
428 | si.lpReserved2 = (LPBYTE)&ch; | |
c90e1cf1 | 429 | si.cbReserved2 = sizeof (ch); |
1fd5e000 | 430 | |
1ec4f618 | 431 | /* Remove impersonation */ |
e40670ee | 432 | if (cygheap->user.issetuid ()) |
57ff940d | 433 | RevertToSelf (); |
1fd5e000 | 434 | |
1ec4f618 | 435 | ch.parent = hParent; |
84aeff41 CF |
436 | #ifdef DEBUGGING |
437 | if (npid_max) | |
438 | { | |
439 | for (int pass = 0; pass < 2; pass++) | |
440 | { | |
441 | pid_t pid; | |
442 | while ((pid = fork_pids[npid++])) | |
443 | if (!pinfo (pid)) | |
444 | { | |
445 | ch.cygpid = pid; | |
446 | goto out; | |
447 | } | |
448 | npid = 0; | |
449 | } | |
450 | } | |
e5ba4c06 | 451 | out: |
84aeff41 | 452 | #endif |
1fd5e000 | 453 | |
1ec4f618 | 454 | char sa_buf[1024]; |
a9917779 | 455 | PSECURITY_ATTRIBUTES sec_attribs = sec_user_nih (sa_buf); |
aece55b9 CF |
456 | syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %x, 0, 0, %p, %p)", |
457 | myself->progname, myself->progname, c_flags, &si, &pi); | |
c7e2187a | 458 | __malloc_lock (); |
e2e07827 CF |
459 | void *newheap; |
460 | newheap = cygheap_setup_for_child (&ch,cygheap->fdtab.need_fixup_before ()); | |
aece55b9 CF |
461 | rc = CreateProcess (myself->progname, /* image to run */ |
462 | myself->progname, /* what we send in arg0 */ | |
a9917779 CV |
463 | sec_attribs, |
464 | sec_attribs, | |
aece55b9 CF |
465 | TRUE, /* inherit handles from parent */ |
466 | c_flags, | |
467 | NULL, /* environment filled in later */ | |
84aeff41 | 468 | 0, /* use current drive/directory */ |
aece55b9 CF |
469 | &si, |
470 | &pi); | |
84c7d409 | 471 | |
1ec4f618 | 472 | CloseHandle (hParent); |
84c7d409 | 473 | |
1ec4f618 CF |
474 | if (!rc) |
475 | { | |
476 | __seterrno (); | |
477 | syscall_printf ("CreateProcessA failed, %E"); | |
c90e1cf1 CF |
478 | ForceCloseHandle (subproc_ready); |
479 | ForceCloseHandle (forker_finished); | |
64b30629 | 480 | /* Restore impersonation */ |
e40670ee | 481 | if (cygheap->user.issetuid ()) |
57ff940d | 482 | ImpersonateLoggedOnUser (cygheap->user.token); |
e2e07827 | 483 | cygheap_setup_for_child_cleanup (newheap, &ch, 0); |
1ec4f618 CF |
484 | return -1; |
485 | } | |
64b30629 | 486 | |
dd4f0b23 CV |
487 | /* Fixup the parent datastructure if needed and resume the child's |
488 | main thread. */ | |
e2e07827 CF |
489 | if (!cygheap->fdtab.need_fixup_before ()) |
490 | cygheap_setup_for_child_cleanup (newheap, &ch, 0); | |
491 | else | |
dd4f0b23 | 492 | { |
0381fec6 | 493 | cygheap->fdtab.fixup_before_fork (pi.dwProcessId); |
e2e07827 | 494 | cygheap_setup_for_child_cleanup (newheap, &ch, 1); |
dd4f0b23 CV |
495 | ResumeThread (pi.hThread); |
496 | } | |
497 | ||
84aeff41 CF |
498 | #ifdef DEBUGGING |
499 | pinfo forked ((ch.cygpid != 1 ? ch.cygpid : cygwin_pid (pi.dwProcessId)), 1); | |
500 | #else | |
1ec4f618 | 501 | pinfo forked (cygwin_pid (pi.dwProcessId), 1); |
84aeff41 | 502 | #endif |
1fd5e000 | 503 | |
1ec4f618 CF |
504 | /* Initialize things that are done later in dll_crt0_1 that aren't done |
505 | for the forkee. */ | |
c90e1cf1 | 506 | strcpy (forked->progname, myself->progname); |
1fd5e000 | 507 | |
1ec4f618 | 508 | /* Restore impersonation */ |
e40670ee | 509 | if (cygheap->user.issetuid ()) |
57ff940d | 510 | ImpersonateLoggedOnUser (cygheap->user.token); |
1fd5e000 | 511 | |
1ec4f618 CF |
512 | ProtectHandle (pi.hThread); |
513 | /* Protect the handle but name it similarly to the way it will | |
514 | be called in subproc handling. */ | |
515 | ProtectHandle1 (pi.hProcess, childhProc); | |
b0de2aa2 | 516 | |
1ec4f618 | 517 | /* Fill in fields in the child's process table entry. */ |
1ec4f618 CF |
518 | forked->hProcess = pi.hProcess; |
519 | forked->dwProcessId = pi.dwProcessId; | |
c90e1cf1 | 520 | forked->copysigs (myself); |
cde0c2fb CF |
521 | |
522 | /* Hopefully, this will succeed. The alternative to doing things this | |
523 | way is to reserve space prior to calling CreateProcess and then fill | |
524 | it in afterwards. This requires more bookkeeping than I like, though, | |
525 | so we'll just do it the easy way. So, terminate any child process if | |
526 | we can't actually record the pid in the internal table. */ | |
527 | if (!forked.remember ()) | |
528 | { | |
529 | TerminateProcess (pi.hProcess, 1); | |
530 | set_errno (EAGAIN); | |
531 | goto cleanup; | |
532 | } | |
533 | ||
534 | slow_pid_reuse (pi.hProcess); | |
1ec4f618 CF |
535 | |
536 | /* Wait for subproc to initialize itself. */ | |
ded25056 | 537 | if (!sync_with_child (pi, subproc_ready, TRUE, "waiting for longjmp")) |
1ec4f618 CF |
538 | goto cleanup; |
539 | ||
540 | /* CHILD IS STOPPED */ | |
541 | debug_printf ("child is alive (but stopped)"); | |
542 | ||
543 | /* Initialize, in order: data, bss, heap, stack, dll data, dll bss | |
544 | Note: variables marked as NO_COPY will not be copied | |
545 | since they are placed in a protected segment. */ | |
1fd5e000 | 546 | |
1fd5e000 | 547 | |
1ec4f618 CF |
548 | MALLOC_CHECK; |
549 | rc = fork_copy (pi, "user/cygwin data", | |
550 | user_data->data_start, user_data->data_end, | |
551 | user_data->bss_start, user_data->bss_end, | |
1ff9f4b9 | 552 | cygheap->heapbase, cygheap->heapptr, |
1ec4f618 CF |
553 | stack_here, ch.stackbottom, |
554 | dll_data_start, dll_data_end, | |
555 | dll_bss_start, dll_bss_end, NULL); | |
1fd5e000 | 556 | |
c7e2187a | 557 | __malloc_unlock (); |
1ec4f618 CF |
558 | MALLOC_CHECK; |
559 | if (!rc) | |
560 | goto cleanup; | |
1fd5e000 | 561 | |
1ec4f618 CF |
562 | /* Now fill data/bss of any DLLs that were linked into the program. */ |
563 | for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ()) | |
564 | { | |
565 | debug_printf ("copying data/bss of a linked dll"); | |
566 | if (!fork_copy (pi, "linked dll data/bss", d->p.data_start, d->p.data_end, | |
567 | d->p.bss_start, d->p.bss_end, | |
568 | NULL)) | |
1fd5e000 | 569 | goto cleanup; |
1fd5e000 | 570 | } |
1fd5e000 | 571 | |
1ec4f618 CF |
572 | /* Start thread, and wait for it to reload dlls. */ |
573 | if (!resume_child (pi, forker_finished) || | |
574 | !sync_with_child (pi, subproc_ready, load_dlls, "child loading dlls")) | |
575 | goto cleanup; | |
1fd5e000 | 576 | |
1ec4f618 CF |
577 | /* If DLLs were loaded in the parent, then the child has reloaded all |
578 | of them and is now waiting to have all of the individual data and | |
579 | bss sections filled in. */ | |
580 | if (load_dlls) | |
581 | { | |
582 | /* CHILD IS STOPPED */ | |
583 | /* write memory of reloaded dlls */ | |
584 | for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ()) | |
1fd5e000 | 585 | { |
1ec4f618 CF |
586 | debug_printf ("copying data/bss for a loaded dll"); |
587 | if (!fork_copy (pi, "loaded dll data/bss", d->p.data_start, d->p.data_end, | |
588 | d->p.bss_start, d->p.bss_end, | |
589 | NULL)) | |
590 | goto cleanup; | |
1fd5e000 | 591 | } |
1ec4f618 CF |
592 | /* Start the child up again. */ |
593 | (void) resume_child (pi, forker_finished); | |
1fd5e000 CF |
594 | } |
595 | ||
1ec4f618 CF |
596 | ForceCloseHandle (subproc_ready); |
597 | ForceCloseHandle (pi.hThread); | |
598 | ForceCloseHandle (forker_finished); | |
599 | forker_finished = NULL; | |
600 | pi.hThread = NULL; | |
f1f13795 | 601 | pthread::atforkparent (); |
1fd5e000 | 602 | |
1ec4f618 | 603 | return forked->pid; |
1fd5e000 CF |
604 | |
605 | /* Common cleanup code for failure cases */ | |
e5ba4c06 | 606 | cleanup: |
1fd5e000 | 607 | /* Remember to de-allocate the fd table. */ |
1fd5e000 CF |
608 | if (pi.hProcess) |
609 | ForceCloseHandle1 (pi.hProcess, childhProc); | |
610 | if (pi.hThread) | |
611 | ForceCloseHandle (pi.hThread); | |
612 | if (subproc_ready) | |
613 | ForceCloseHandle (subproc_ready); | |
614 | if (forker_finished) | |
615 | ForceCloseHandle (forker_finished); | |
1fd5e000 CF |
616 | return -1; |
617 | } | |
618 | ||
1ec4f618 CF |
619 | extern "C" int |
620 | fork () | |
1fd5e000 | 621 | { |
1ec4f618 CF |
622 | struct |
623 | { | |
624 | HANDLE hParent; | |
625 | dll *first_dll; | |
626 | bool load_dlls; | |
627 | } grouped; | |
628 | ||
1ec4f618 | 629 | MALLOC_CHECK; |
ad30b4ff | 630 | sigframe thisframe (mainthread); |
1ec4f618 | 631 | |
1ec4f618 | 632 | debug_printf ("entering"); |
aece55b9 CF |
633 | grouped.hParent = grouped.first_dll = NULL; |
634 | grouped.load_dlls = 0; | |
1ec4f618 CF |
635 | |
636 | if (ISSTATE(myself, PID_SPLIT_HEAP)) | |
637 | { | |
638 | system_printf ("The heap has been split, CYGWIN can't fork this process."); | |
639 | system_printf ("Increase the heap_chunk_size in the registry and try again."); | |
640 | set_errno (ENOMEM); | |
641 | syscall_printf ("-1 = fork (), split heap"); | |
642 | return -1; | |
643 | } | |
644 | ||
aece55b9 | 645 | void *esp; |
20a2c443 | 646 | __asm__ volatile ("movl %%esp,%0": "=r" (esp)); |
aece55b9 | 647 | |
f8f9b12e CF |
648 | myself->set_has_pgid_children (); |
649 | ||
1ec4f618 | 650 | child_info_fork ch; |
1ec4f618 | 651 | |
aece55b9 CF |
652 | int res = setjmp (ch.jmp); |
653 | ||
654 | if (res) | |
1ec4f618 CF |
655 | res = fork_child (grouped.hParent, grouped.first_dll, grouped.load_dlls); |
656 | else | |
20a2c443 | 657 | res = fork_parent (grouped.hParent, grouped.first_dll, grouped.load_dlls, esp, ch); |
1ec4f618 CF |
658 | |
659 | MALLOC_CHECK; | |
660 | syscall_printf ("%d = fork()", res); | |
661 | return res; | |
1fd5e000 | 662 | } |
84aeff41 CF |
663 | #ifdef DEBUGGING |
664 | void | |
665 | fork_init () | |
666 | { | |
667 | char buf[1024]; | |
668 | if (!GetEnvironmentVariable ("CYGWIN_FORK_PIDS", buf, 1024)) | |
669 | return; | |
670 | pid_t pid; | |
671 | char *p, *pe; | |
672 | for (p = buf; (pid = strtol (p, &pe, 10)); p = pe) | |
673 | fork_pids[npid_max++] = pid; | |
674 | } | |
675 | #endif /*DEBUGGING*/ | |
1fd5e000 CF |
676 | |
677 | #ifdef NEWVFORK | |
678 | /* Dummy function to force second assignment below to actually be | |
679 | carried out */ | |
680 | static vfork_save * | |
681 | get_vfork_val () | |
682 | { | |
683 | return vfork_storage.val (); | |
684 | } | |
685 | #endif | |
686 | ||
8dca9e23 | 687 | extern "C" int |
1fd5e000 CF |
688 | vfork () |
689 | { | |
690 | #ifndef NEWVFORK | |
691 | return fork (); | |
692 | #else | |
9661a0c8 | 693 | sigframe thisframe; |
1fd5e000 | 694 | vfork_save *vf = get_vfork_val (); |
47026c07 | 695 | char **esp, **pp; |
1fd5e000 CF |
696 | |
697 | if (vf == NULL) | |
698 | vf = vfork_storage.create (); | |
25e40ae6 CF |
699 | else if (vf->pid) |
700 | return fork (); | |
1fd5e000 CF |
701 | |
702 | if (!setjmp (vf->j)) | |
703 | { | |
704 | vf->pid = -1; | |
47026c07 | 705 | __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):); |
1fd5e000 | 706 | __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):); |
47026c07 | 707 | for (pp = (char **)vf->frame, esp = vf->vfork_esp; |
9661a0c8 | 708 | esp <= vf->vfork_ebp + 2; pp++, esp++) |
47026c07 | 709 | *pp = *esp; |
8dca9e23 CF |
710 | vf->ctty = myself->ctty; |
711 | vf->sid = myself->sid; | |
712 | vf->pgid = myself->pgid; | |
12520587 CF |
713 | int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1; |
714 | debug_printf ("%d = vfork()", res); | |
715 | return res; | |
1fd5e000 CF |
716 | } |
717 | ||
1fd5e000 | 718 | vf = get_vfork_val (); |
e2e07827 | 719 | |
e2e07827 | 720 | for (pp = (char **)vf->frame, esp = vf->vfork_esp; |
9661a0c8 | 721 | esp <= vf->vfork_ebp + 2; pp++, esp++) |
e2e07827 CF |
722 | *esp = *pp; |
723 | ||
9661a0c8 CF |
724 | thisframe.init (mainthread); |
725 | cygheap->fdtab.vfork_parent_restore (); | |
726 | ||
8dca9e23 CF |
727 | myself->ctty = vf->ctty; |
728 | myself->sid = vf->sid; | |
729 | myself->pgid = vf->pgid; | |
730 | ||
1fd5e000 CF |
731 | if (vf->pid < 0) |
732 | { | |
8dca9e23 | 733 | int exitval = vf->exitval; |
5654f240 | 734 | vf->pid = 0; |
1fd5e000 CF |
735 | if ((vf->pid = fork ()) == 0) |
736 | exit (exitval); | |
737 | } | |
738 | ||
25e40ae6 CF |
739 | int pid = vf->pid; |
740 | vf->pid = 0; | |
8af0f81d | 741 | debug_printf ("exiting vfork, pid %d", pid); |
9661a0c8 | 742 | sig_dispatch_pending (); |
25e40ae6 | 743 | return pid; |
1fd5e000 CF |
744 | #endif |
745 | } |