]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* fork.cc |
2 | ||
0b7c56a5 | 3 | Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, |
a7d2cc16 | 4 | 2007, 2008 Red Hat, Inc. |
1fd5e000 CF |
5 | |
6 | This file is part of Cygwin. | |
7 | ||
8 | This software is a copyrighted work licensed under the terms of the | |
9 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
10 | details. */ | |
11 | ||
4c8d72de | 12 | #include "winsup.h" |
1fd5e000 CF |
13 | #include <stdio.h> |
14 | #include <unistd.h> | |
15 | #include <stdlib.h> | |
169c465a | 16 | #include "cygerrno.h" |
6b91b8d5 | 17 | #include "security.h" |
47063f00 | 18 | #include "path.h" |
7ac61736 | 19 | #include "fhandler.h" |
e2ebe117 | 20 | #include "dtable.h" |
bccd5e0d CF |
21 | #include "sigproc.h" |
22 | #include "pinfo.h" | |
b0e82b74 | 23 | #include "cygheap.h" |
488c7683 | 24 | #include "child_info.h" |
8cb359d9 | 25 | #include "cygtls.h" |
752b16ce | 26 | #include "tls_pbuf.h" |
f0338f54 CF |
27 | #include "perprocess.h" |
28 | #include "dll_init.h" | |
c7e2187a | 29 | #include "cygmalloc.h" |
1fd5e000 | 30 | |
22cf17b3 | 31 | #define NPIDS_HELD 4 |
a9f36d28 | 32 | |
1fd5e000 CF |
33 | /* Timeout to wait for child to start, parent to init child, etc. */ |
34 | /* FIXME: Once things stabilize, bump up to a few minutes. */ | |
35 | #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ | |
36 | ||
280fdd0b CF |
37 | class frok |
38 | { | |
39 | dll *first_dll; | |
40 | bool load_dlls; | |
41 | child_info_fork ch; | |
42 | const char *error; | |
43 | int child_pid; | |
44 | int this_errno; | |
39fc0d36 CF |
45 | int __stdcall parent (volatile char * volatile here); |
46 | int __stdcall child (volatile char * volatile here); | |
280fdd0b CF |
47 | friend int fork (); |
48 | }; | |
49 | ||
39fc0d36 CF |
50 | class lock_signals |
51 | { | |
52 | bool worked; | |
53 | public: | |
54 | lock_signals () | |
55 | { | |
56 | worked = sig_send (NULL, __SIGHOLD) == 0; | |
57 | } | |
58 | operator int () const | |
59 | { | |
60 | return worked; | |
61 | } | |
62 | void dont_bother () | |
63 | { | |
64 | worked = false; | |
65 | } | |
66 | ~lock_signals () | |
67 | { | |
68 | if (worked) | |
69 | sig_send (NULL, __SIGNOHOLD); | |
70 | } | |
71 | }; | |
72 | ||
73 | class lock_pthread | |
74 | { | |
75 | bool bother; | |
76 | public: | |
77 | lock_pthread (): bother (1) | |
78 | { | |
79 | pthread::atforkprepare (); | |
80 | } | |
81 | void dont_bother () | |
82 | { | |
83 | bother = false; | |
84 | } | |
85 | ~lock_pthread () | |
86 | { | |
87 | if (bother) | |
88 | pthread::atforkparent (); | |
89 | } | |
90 | }; | |
91 | ||
92 | class hold_everything | |
93 | { | |
e943a1a3 | 94 | public: /* DELETEME*/ |
39fc0d36 CF |
95 | bool& ischild; |
96 | /* Note the order of the locks below. It is important, | |
97 | to avoid races, that the lock order be preserved. | |
7b44665a | 98 | |
39fc0d36 CF |
99 | pthread is first because it serves as a master lock |
100 | against other forks being attempted while this one is active. | |
7b44665a | 101 | |
39fc0d36 CF |
102 | signals is next to stop signal processing for the duration |
103 | of the fork. | |
104 | ||
105 | process is last. If it is put before signals, then a deadlock | |
106 | could be introduced if the process attempts to exit due to a signal. */ | |
107 | lock_pthread pthread; | |
108 | lock_signals signals; | |
109 | lock_process process; | |
110 | ||
111 | public: | |
112 | hold_everything (bool& x): ischild (x) {} | |
113 | operator int () const {return signals;} | |
114 | ||
115 | ~hold_everything() | |
116 | { | |
117 | if (ischild) | |
118 | { | |
119 | pthread.dont_bother (); | |
120 | process.dont_bother (); | |
121 | signals.dont_bother (); | |
122 | } | |
123 | } | |
124 | ||
125 | }; | |
126 | ||
bbca1e4c | 127 | static void |
54dd79bb | 128 | resume_child (HANDLE forker_finished) |
1fd5e000 | 129 | { |
1fd5e000 | 130 | SetEvent (forker_finished); |
1ec4f618 | 131 | debug_printf ("signalled child"); |
bbca1e4c | 132 | return; |
1fd5e000 CF |
133 | } |
134 | ||
3178cfff | 135 | /* Notify parent that it is time for the next step. */ |
1ec4f618 | 136 | static void __stdcall |
c90e1cf1 | 137 | sync_with_parent (const char *s, bool hang_self) |
1fd5e000 | 138 | { |
1ec4f618 | 139 | debug_printf ("signalling parent: %s", s); |
54dd79bb | 140 | fork_info->ready (false); |
1ec4f618 CF |
141 | if (hang_self) |
142 | { | |
6ea3e429 | 143 | HANDLE h = fork_info->forker_finished; |
1ec4f618 CF |
144 | /* Wait for the parent to fill in our stack and heap. |
145 | Don't wait forever here. If our parent dies we don't want to clog | |
146 | the system. If the wait fails, we really can't continue so exit. */ | |
147 | DWORD psync_rc = WaitForSingleObject (h, FORK_WAIT_TIMEOUT); | |
148 | debug_printf ("awake"); | |
149 | switch (psync_rc) | |
150 | { | |
151 | case WAIT_TIMEOUT: | |
e431827c | 152 | api_fatal ("WFSO timed out %s", s); |
1ec4f618 CF |
153 | break; |
154 | case WAIT_FAILED: | |
155 | if (GetLastError () == ERROR_INVALID_HANDLE && | |
6ea3e429 | 156 | WaitForSingleObject (fork_info->forker_finished, 1) != WAIT_FAILED) |
1ec4f618 | 157 | break; |
e431827c | 158 | api_fatal ("WFSO failed %s, fork_finished %p, %E", s, |
6ea3e429 | 159 | fork_info->forker_finished); |
1ec4f618 CF |
160 | break; |
161 | default: | |
162 | debug_printf ("no problems"); | |
163 | break; | |
164 | } | |
165 | } | |
1fd5e000 CF |
166 | } |
167 | ||
280fdd0b | 168 | int __stdcall |
39fc0d36 | 169 | frok::child (volatile char * volatile here) |
1fd5e000 | 170 | { |
280fdd0b | 171 | HANDLE& hParent = ch.parent; |
a998dd70 | 172 | extern void fixup_lockf_after_fork (); |
b1d9a0bd | 173 | extern void fixup_hooks_after_fork (); |
f6936c48 | 174 | extern void fixup_timers_after_fork (); |
1ec4f618 CF |
175 | debug_printf ("child is running. pid %d, ppid %d, stack here %p", |
176 | myself->pid, myself->ppid, __builtin_frame_address (0)); | |
1ec4f618 | 177 | |
2e008fb9 | 178 | sync_with_parent ("after longjmp", true); |
f70389b5 | 179 | sigproc_printf ("hParent %p, child 1 first_dll %p, load_dlls %d", hParent, |
1ff9f4b9 | 180 | first_dll, load_dlls); |
1fd5e000 | 181 | |
e431827c CF |
182 | /* If we've played with the stack, stacksize != 0. That means that |
183 | fork() was invoked from other than the main thread. Make sure that | |
184 | the threadinfo information is properly set up. */ | |
0e061ecf | 185 | if (fork_info->stacksize) |
e431827c CF |
186 | { |
187 | _main_tls = &_my_tls; | |
188 | _main_tls->init_thread (NULL, NULL); | |
189 | _main_tls->local_clib = *_impure_ptr; | |
190 | _impure_ptr = &_main_tls->local_clib; | |
191 | } | |
192 | ||
a76877e9 CV |
193 | set_cygwin_privileges (hProcToken); |
194 | clear_procimptoken (); | |
195 | cygheap->user.reimpersonate (); | |
f4a1f8a1 | 196 | |
1ec4f618 | 197 | #ifdef DEBUGGING |
5ab0b5cf | 198 | if (GetEnvironmentVariableA ("FORKDEBUG", NULL, 0)) |
1ec4f618 CF |
199 | try_to_debug (); |
200 | char buf[80]; | |
201 | /* This is useful for debugging fork problems. Use gdb to attach to | |
202 | the pid reported here. */ | |
5ab0b5cf | 203 | if (GetEnvironmentVariableA ("CYGWIN_FORK_SLEEP", buf, sizeof (buf))) |
1ec4f618 CF |
204 | { |
205 | small_printf ("Sleeping %d after fork, pid %u\n", atoi (buf), GetCurrentProcessId ()); | |
c90e1cf1 | 206 | Sleep (atoi (buf)); |
1ec4f618 CF |
207 | } |
208 | #endif | |
1fd5e000 | 209 | |
4c15b7ab ED |
210 | set_file_api_mode (current_codepage); |
211 | ||
1ec4f618 | 212 | MALLOC_CHECK; |
1fd5e000 | 213 | |
b6e69d53 CV |
214 | #ifdef USE_SERVER |
215 | /* Incredible but true: If we use sockets and SYSV IPC shared memory, | |
216 | there's a good chance that a duplicated socket in the child occupies | |
217 | memory which is needed to duplicate shared memory from the parent | |
218 | process, if the shared memory hasn't been duplicated already. | |
219 | The same goes very likely for "normal" mmap shared memory, too, but | |
220 | with SYSV IPC it was the first time observed. So, *never* fixup | |
221 | fdtab before fixing up shared memory. */ | |
222 | if (fixup_shms_after_fork ()) | |
223 | api_fatal ("recreate_shm areas after fork failed"); | |
224 | #endif | |
5ec14fe4 | 225 | |
1ec4f618 CF |
226 | MALLOC_CHECK; |
227 | ||
228 | /* If we haven't dynamically loaded any dlls, just signal | |
229 | the parent. Otherwise, load all the dlls, tell the parent | |
230 | that we're done, and wait for the parent to fill in the. | |
231 | loaded dlls' data/bss. */ | |
232 | if (!load_dlls) | |
d525130f CF |
233 | { |
234 | cygheap->fdtab.fixup_after_fork (hParent); | |
2e008fb9 | 235 | sync_with_parent ("performed fork fixup", false); |
d525130f | 236 | } |
1ec4f618 | 237 | else |
1fd5e000 | 238 | { |
1ec4f618 | 239 | dlls.load_after_fork (hParent, first_dll); |
d525130f | 240 | cygheap->fdtab.fixup_after_fork (hParent); |
2e008fb9 | 241 | sync_with_parent ("loaded dlls", true); |
1fd5e000 CF |
242 | } |
243 | ||
a9396868 | 244 | init_console_handler (myself->ctty >= 0); |
0c55f6ed | 245 | ForceCloseHandle1 (fork_info->forker_finished, forker_finished); |
2eb392bd | 246 | |
f1f13795 | 247 | pthread::atforkchild (); |
f6936c48 | 248 | fixup_timers_after_fork (); |
166b2571 | 249 | cygbench ("fork-child"); |
b21413b3 | 250 | ld_preload (); |
f02b22dc | 251 | fixup_hooks_after_fork (); |
f02b22dc | 252 | _my_tls.fixup_after_fork (); |
12b33712 | 253 | wait_for_sigthread (true); |
f359a29f | 254 | cygwin_finished_initializing = true; |
1ec4f618 CF |
255 | return 0; |
256 | } | |
1fd5e000 | 257 | |
280fdd0b | 258 | #define NO_SLOW_PID_REUSE |
5d9a7c87 | 259 | #ifndef NO_SLOW_PID_REUSE |
84aeff41 CF |
260 | static void |
261 | slow_pid_reuse (HANDLE h) | |
262 | { | |
24515d65 CF |
263 | static NO_COPY HANDLE last_fork_procs[NPIDS_HELD]; |
264 | static NO_COPY unsigned nfork_procs; | |
84aeff41 | 265 | |
5ba05cab | 266 | if (nfork_procs >= (sizeof (last_fork_procs) / sizeof (last_fork_procs [0]))) |
84aeff41 | 267 | nfork_procs = 0; |
54dd79bb | 268 | /* Keep a list of handles to child processes sitting around to prevent |
84aeff41 CF |
269 | Windows from reusing the same pid n times in a row. Having the same pids |
270 | close in succesion confuses bash. Keeping a handle open will stop | |
271 | windows from reusing the same pid. */ | |
272 | if (last_fork_procs[nfork_procs]) | |
5ba05cab CF |
273 | ForceCloseHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
274 | if (DuplicateHandle (hMainProc, h, hMainProc, &last_fork_procs[nfork_procs], | |
84aeff41 | 275 | 0, FALSE, DUPLICATE_SAME_ACCESS)) |
5ba05cab CF |
276 | ProtectHandle1 (last_fork_procs[nfork_procs], fork_stupidity); |
277 | else | |
84aeff41 CF |
278 | { |
279 | last_fork_procs[nfork_procs] = NULL; | |
280 | system_printf ("couldn't create last_fork_proc, %E"); | |
281 | } | |
282 | nfork_procs++; | |
283 | } | |
89e7a1ce | 284 | #endif |
84aeff41 | 285 | |
280fdd0b | 286 | int __stdcall |
39fc0d36 | 287 | frok::parent (volatile char * volatile stack_here) |
1ec4f618 | 288 | { |
54dd79bb | 289 | HANDLE forker_finished; |
1ec4f618 | 290 | DWORD rc; |
280fdd0b CF |
291 | child_pid = -1; |
292 | error = NULL; | |
293 | this_errno = 0; | |
294 | bool fix_impersonation = false; | |
295 | pinfo child; | |
a9396868 | 296 | static char errbuf[256]; |
1fd5e000 | 297 | |
a743e3b9 | 298 | int c_flags = GetPriorityClass (hMainProc); |
0dc24975 | 299 | debug_printf ("priority class %d", c_flags); |
1ec4f618 CF |
300 | |
301 | /* If we don't have a console, then don't create a console for the | |
302 | child either. */ | |
580e99a1 CF |
303 | HANDLE console_handle = CreateFile ("CONOUT$", GENERIC_WRITE, |
304 | FILE_SHARE_WRITE, &sec_none_nih, | |
305 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, | |
306 | NULL); | |
1ec4f618 | 307 | |
580e99a1 | 308 | if (console_handle != INVALID_HANDLE_VALUE) |
1ec4f618 CF |
309 | CloseHandle (console_handle); |
310 | else | |
311 | c_flags |= DETACHED_PROCESS; | |
1fd5e000 | 312 | |
dd4f0b23 CV |
313 | /* Some file types (currently only sockets) need extra effort in the |
314 | parent after CreateProcess and before copying the datastructures | |
315 | to the child. So we have to start the child in suspend state, | |
316 | unfortunately, to avoid a race condition. */ | |
0381fec6 | 317 | if (cygheap->fdtab.need_fixup_before ()) |
dd4f0b23 CV |
318 | c_flags |= CREATE_SUSPENDED; |
319 | ||
1ec4f618 CF |
320 | /* Remember the address of the first loaded dll and decide |
321 | if we need to load dlls. We do this here so that this | |
322 | information will be available in the parent and, when | |
323 | the stack is copied, in the child. */ | |
324 | first_dll = dlls.start.next; | |
325 | load_dlls = dlls.reload_on_fork && dlls.loaded_dlls; | |
1fd5e000 | 326 | |
1ec4f618 CF |
327 | /* This will help some of the confusion. */ |
328 | fflush (stdout); | |
1fd5e000 | 329 | |
1ec4f618 CF |
330 | forker_finished = CreateEvent (&sec_all, FALSE, FALSE, NULL); |
331 | if (forker_finished == NULL) | |
332 | { | |
280fdd0b | 333 | this_errno = geterrno_from_win_error (); |
40c7d132 | 334 | error = "unable to allocate forker_finished event"; |
1ec4f618 CF |
335 | return -1; |
336 | } | |
1fd5e000 | 337 | |
0301bfd0 | 338 | ProtectHandleINH (forker_finished); |
1fd5e000 | 339 | |
1ec4f618 | 340 | ch.forker_finished = forker_finished; |
1fd5e000 | 341 | |
0dc24975 | 342 | ch.stackbottom = _tlsbase; |
39fc0d36 | 343 | ch.stacktop = (void *) stack_here; |
0dc24975 CF |
344 | ch.stacksize = (char *) ch.stackbottom - (char *) stack_here; |
345 | debug_printf ("stack - bottom %p, top %p, size %d", | |
346 | ch.stackbottom, ch.stacktop, ch.stacksize); | |
1fd5e000 | 347 | |
bbca1e4c | 348 | PROCESS_INFORMATION pi; |
752b16ce | 349 | STARTUPINFOW si; |
bbca1e4c CF |
350 | |
351 | memset (&si, 0, sizeof (si)); | |
752b16ce | 352 | si.cb = sizeof si; |
c6674b53 | 353 | |
54dd79bb | 354 | si.lpReserved2 = (LPBYTE) &ch; |
c90e1cf1 | 355 | si.cbReserved2 = sizeof (ch); |
1fd5e000 | 356 | |
752b16ce CV |
357 | /* FIXME: myself->progname should be converted to WCHAR. */ |
358 | tmp_pathbuf tp; | |
359 | PWCHAR progname = tp.w_get (); | |
360 | sys_mbstowcs (progname, NT_MAX_PATH, myself->progname); | |
361 | ||
362 | syscall_printf ("CreateProcess (%W, %W, 0, 0, 1, %p, 0, 0, %p, %p)", | |
363 | progname, progname, c_flags, &si, &pi); | |
12b33712 CF |
364 | bool locked = __malloc_lock (); |
365 | time_t start_time = time (NULL); | |
366 | ||
1ec4f618 | 367 | /* Remove impersonation */ |
70249d56 | 368 | cygheap->user.deimpersonate (); |
280fdd0b | 369 | fix_impersonation = true; |
1fd5e000 | 370 | |
84d38174 | 371 | while (1) |
1ec4f618 | 372 | { |
752b16ce CV |
373 | rc = CreateProcessW (progname, /* image to run */ |
374 | progname, /* what we send in arg0 */ | |
375 | &sec_none_nih, | |
376 | &sec_none_nih, | |
377 | TRUE, /* inherit handles from parent */ | |
378 | c_flags, | |
379 | NULL, /* environment filled in later */ | |
380 | 0, /* use current drive/directory */ | |
381 | &si, | |
382 | &pi); | |
84d38174 CF |
383 | |
384 | if (!rc) | |
385 | { | |
386 | this_errno = geterrno_from_win_error (); | |
752b16ce | 387 | error = "CreateProcessW failed"; |
84d38174 CF |
388 | memset (&pi, 0, sizeof (pi)); |
389 | goto cleanup; | |
390 | } | |
64b30629 | 391 | |
84d38174 CF |
392 | /* Fixup the parent datastructure if needed and resume the child's |
393 | main thread. */ | |
394 | if (c_flags & CREATE_SUSPENDED) | |
395 | { | |
396 | cygheap->fdtab.fixup_before_fork (pi.dwProcessId); | |
397 | ResumeThread (pi.hThread); | |
398 | } | |
dd4f0b23 | 399 | |
a9396868 CF |
400 | CloseHandle (pi.hThread); |
401 | ||
402 | /* Protect the handle but name it similarly to the way it will | |
403 | be called in subproc handling. */ | |
404 | ProtectHandle1 (pi.hProcess, childhProc); | |
405 | ||
84d38174 CF |
406 | strace.write_childpid (ch, pi.dwProcessId); |
407 | ||
408 | /* Wait for subproc to initialize itself. */ | |
409 | if (!ch.sync (pi.dwProcessId, pi.hProcess, FORK_WAIT_TIMEOUT)) | |
410 | { | |
a9396868 | 411 | DWORD exit_code = ch.proc_retry (pi.hProcess); |
f02400f7 CF |
412 | if (!exit_code) |
413 | continue; | |
84d38174 | 414 | this_errno = EAGAIN; |
67f85ee7 | 415 | /* Not thread safe, but do we care? */ |
a9396868 | 416 | __small_sprintf (errbuf, "died waiting for longjmp before initialization, " |
67f85ee7 | 417 | "retry %d, exit code %p", ch.retry, exit_code); |
a9396868 | 418 | error = errbuf; |
84d38174 CF |
419 | goto cleanup; |
420 | } | |
421 | break; | |
422 | } | |
5d970405 | 423 | |
12b33712 CF |
424 | /* Restore impersonation */ |
425 | cygheap->user.reimpersonate (); | |
426 | fix_impersonation = false; | |
427 | ||
280fdd0b CF |
428 | child_pid = cygwin_pid (pi.dwProcessId); |
429 | child.init (child_pid, 1, NULL); | |
72067cca | 430 | |
54dd79bb | 431 | if (!child) |
6c68fbbc | 432 | { |
280fdd0b CF |
433 | this_errno = get_errno () == ENOMEM ? ENOMEM : EAGAIN; |
434 | #ifdef DEBUGGING | |
40c7d132 | 435 | error = "pinfo failed"; |
280fdd0b | 436 | #else |
6c68fbbc | 437 | syscall_printf ("pinfo failed"); |
280fdd0b | 438 | #endif |
6c68fbbc CF |
439 | goto cleanup; |
440 | } | |
1fd5e000 | 441 | |
84d38174 | 442 | child->start_time = start_time; /* Register child's starting time. */ |
f834829d CF |
443 | child->nice = myself->nice; |
444 | ||
1ec4f618 CF |
445 | /* Initialize things that are done later in dll_crt0_1 that aren't done |
446 | for the forkee. */ | |
54dd79bb | 447 | strcpy (child->progname, myself->progname); |
1fd5e000 | 448 | |
1ec4f618 | 449 | /* Fill in fields in the child's process table entry. */ |
54dd79bb CF |
450 | child->dwProcessId = pi.dwProcessId; |
451 | child.hProcess = pi.hProcess; | |
cde0c2fb CF |
452 | |
453 | /* Hopefully, this will succeed. The alternative to doing things this | |
454 | way is to reserve space prior to calling CreateProcess and then fill | |
455 | it in afterwards. This requires more bookkeeping than I like, though, | |
456 | so we'll just do it the easy way. So, terminate any child process if | |
457 | we can't actually record the pid in the internal table. */ | |
4ee52924 | 458 | if (!child.remember (false)) |
cde0c2fb CF |
459 | { |
460 | TerminateProcess (pi.hProcess, 1); | |
280fdd0b | 461 | this_errno = EAGAIN; |
40c7d132 CF |
462 | #ifdef DEBUGGING0 |
463 | error = "child.remember failed"; | |
280fdd0b | 464 | #endif |
cde0c2fb CF |
465 | goto cleanup; |
466 | } | |
467 | ||
5d9a7c87 | 468 | #ifndef NO_SLOW_PID_REUSE |
cde0c2fb | 469 | slow_pid_reuse (pi.hProcess); |
89e7a1ce | 470 | #endif |
1ec4f618 | 471 | |
1ec4f618 CF |
472 | /* CHILD IS STOPPED */ |
473 | debug_printf ("child is alive (but stopped)"); | |
474 | ||
12b33712 CF |
475 | /* Initialize, in order: stack, dll data, dll bss. |
476 | data, bss, heap were done earlier (in dcrt0.cc) | |
477 | Note: variables marked as NO_COPY will not be copied since they are | |
478 | placed in a protected segment. */ | |
1fd5e000 | 479 | |
1ec4f618 | 480 | MALLOC_CHECK; |
ad02bb70 CF |
481 | const void *impure_beg; |
482 | const void *impure_end; | |
483 | const char *impure; | |
29d52c8a | 484 | if (&_my_tls == _main_tls) |
ad02bb70 | 485 | impure_beg = impure_end = impure = NULL; |
29d52c8a CF |
486 | else |
487 | { | |
ad02bb70 | 488 | impure = "impure"; |
29d52c8a CF |
489 | impure_beg = _impure_ptr; |
490 | impure_end = _impure_ptr + 1; | |
491 | } | |
ad02bb70 CF |
492 | rc = child_copy (pi.hProcess, true, |
493 | "stack", stack_here, ch.stackbottom, | |
494 | impure, impure_beg, impure_end, | |
495 | NULL); | |
1fd5e000 | 496 | |
c7e2187a | 497 | __malloc_unlock (); |
e431827c | 498 | locked = false; |
1ec4f618 CF |
499 | MALLOC_CHECK; |
500 | if (!rc) | |
bbca1e4c CF |
501 | { |
502 | this_errno = get_errno (); | |
a9396868 CF |
503 | DWORD exit_code; |
504 | if (!GetExitCodeProcess (pi.hProcess, &exit_code)) | |
505 | exit_code = 0xdeadbeef; | |
506 | __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code); | |
507 | error = errbuf; | |
bbca1e4c CF |
508 | goto cleanup; |
509 | } | |
1fd5e000 | 510 | |
1ec4f618 CF |
511 | /* Now fill data/bss of any DLLs that were linked into the program. */ |
512 | for (dll *d = dlls.istart (DLL_LINK); d; d = dlls.inext ()) | |
513 | { | |
514 | debug_printf ("copying data/bss of a linked dll"); | |
ad02bb70 CF |
515 | if (!child_copy (pi.hProcess, true, |
516 | "linked dll data", d->p.data_start, d->p.data_end, | |
517 | "linked dll bss", d->p.bss_start, d->p.bss_end, | |
518 | NULL)) | |
280fdd0b CF |
519 | { |
520 | this_errno = get_errno (); | |
521 | #ifdef DEBUGGING | |
a9396868 CF |
522 | DWORD exit_code; |
523 | if (!GetExitCodeProcess (pi.hProcess, &exit_code)) | |
524 | exit_code = 0xdeadbeef; | |
525 | __small_sprintf (errbuf, "pid %u, exitval %p", pi.dwProcessId, exit_code); | |
526 | error = errbuf; | |
280fdd0b CF |
527 | #endif |
528 | goto cleanup; | |
529 | } | |
1fd5e000 | 530 | } |
1fd5e000 | 531 | |
bbca1e4c CF |
532 | /* Start thread, and then wait for it to reload dlls. */ |
533 | resume_child (forker_finished); | |
534 | if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT)) | |
54dd79bb | 535 | { |
280fdd0b | 536 | this_errno = EAGAIN; |
40c7d132 | 537 | error = "died waiting for dll loading"; |
54dd79bb CF |
538 | goto cleanup; |
539 | } | |
1fd5e000 | 540 | |
1ec4f618 CF |
541 | /* If DLLs were loaded in the parent, then the child has reloaded all |
542 | of them and is now waiting to have all of the individual data and | |
543 | bss sections filled in. */ | |
544 | if (load_dlls) | |
545 | { | |
546 | /* CHILD IS STOPPED */ | |
547 | /* write memory of reloaded dlls */ | |
548 | for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ()) | |
1fd5e000 | 549 | { |
1ec4f618 | 550 | debug_printf ("copying data/bss for a loaded dll"); |
ad02bb70 CF |
551 | if (!child_copy (pi.hProcess, true, |
552 | "loaded dll data", d->p.data_start, d->p.data_end, | |
553 | "loaded dll bss", d->p.bss_start, d->p.bss_end, | |
554 | NULL)) | |
280fdd0b CF |
555 | { |
556 | this_errno = get_errno (); | |
557 | #ifdef DEBUGGING | |
40c7d132 | 558 | error = "copying data/bss for a loaded dll"; |
280fdd0b CF |
559 | #endif |
560 | goto cleanup; | |
561 | } | |
1fd5e000 | 562 | } |
1ec4f618 | 563 | /* Start the child up again. */ |
0c55f6ed | 564 | resume_child (forker_finished); |
1fd5e000 CF |
565 | } |
566 | ||
1ec4f618 CF |
567 | ForceCloseHandle (forker_finished); |
568 | forker_finished = NULL; | |
1fd5e000 | 569 | |
54dd79bb | 570 | return child_pid; |
1fd5e000 CF |
571 | |
572 | /* Common cleanup code for failure cases */ | |
280fdd0b CF |
573 | cleanup: |
574 | if (fix_impersonation) | |
575 | cygheap->user.reimpersonate (); | |
e431827c CF |
576 | if (locked) |
577 | __malloc_unlock (); | |
578 | ||
1fd5e000 | 579 | /* Remember to de-allocate the fd table. */ |
a743e3b9 | 580 | if (pi.hProcess && !child.hProcess) |
1fd5e000 | 581 | ForceCloseHandle1 (pi.hProcess, childhProc); |
1fd5e000 CF |
582 | if (forker_finished) |
583 | ForceCloseHandle (forker_finished); | |
280fdd0b | 584 | debug_printf ("returning -1"); |
1fd5e000 CF |
585 | return -1; |
586 | } | |
587 | ||
1ec4f618 CF |
588 | extern "C" int |
589 | fork () | |
1fd5e000 | 590 | { |
280fdd0b | 591 | frok grouped; |
1ec4f618 | 592 | |
1ec4f618 | 593 | debug_printf ("entering"); |
ce95c640 | 594 | grouped.first_dll = NULL; |
aece55b9 | 595 | grouped.load_dlls = 0; |
1ec4f618 | 596 | |
f02b22dc | 597 | int res; |
39fc0d36 | 598 | bool ischild = false; |
f02b22dc | 599 | |
f8f9b12e CF |
600 | myself->set_has_pgid_children (); |
601 | ||
ce95c640 CF |
602 | if (grouped.ch.parent == NULL) |
603 | return -1; | |
604 | if (grouped.ch.subproc_ready == NULL) | |
54dd79bb CF |
605 | { |
606 | system_printf ("unable to allocate subproc_ready event, %E"); | |
607 | return -1; | |
608 | } | |
1ec4f618 | 609 | |
39fc0d36 CF |
610 | { |
611 | hold_everything held_everything (ischild); | |
ede284de | 612 | |
39fc0d36 CF |
613 | if (!held_everything) |
614 | { | |
615 | if (exit_state) | |
616 | Sleep (INFINITE); | |
617 | set_errno (EAGAIN); | |
618 | return -1; | |
619 | } | |
7912bcbf | 620 | |
39fc0d36 | 621 | ischild = !!setjmp (grouped.ch.jmp); |
7912bcbf | 622 | |
39fc0d36 CF |
623 | volatile char * volatile esp; |
624 | __asm__ volatile ("movl %%esp,%0": "=r" (esp)); | |
625 | ||
39fc0d36 | 626 | if (!ischild) |
81010d21 | 627 | res = grouped.parent (esp); |
39fc0d36 | 628 | else |
e943a1a3 CF |
629 | { |
630 | res = grouped.child (esp); | |
631 | ischild = true; /* might have been reset by fork mem copy */ | |
632 | } | |
39fc0d36 | 633 | } |
1ec4f618 CF |
634 | |
635 | MALLOC_CHECK; | |
280fdd0b CF |
636 | if (ischild || res > 0) |
637 | /* everything is ok */; | |
638 | else | |
639 | { | |
640 | if (!grouped.error) | |
40c7d132 | 641 | syscall_printf ("fork failed - child pid %d, errno %d", grouped.child_pid, grouped.this_errno); |
280fdd0b | 642 | else |
40c7d132 CF |
643 | { |
644 | char buf[strlen (grouped.error) + sizeof ("child %d - , errno 4294967295 ")]; | |
645 | strcpy (buf, "child %d - "); | |
646 | strcat (buf, grouped.error); | |
647 | strcat (buf, ", errno %d"); | |
648 | system_printf (buf, grouped.child_pid, grouped.this_errno); | |
649 | } | |
650 | ||
280fdd0b CF |
651 | set_errno (grouped.this_errno); |
652 | } | |
a591389d | 653 | syscall_printf ("%d = fork()", res); |
1ec4f618 | 654 | return res; |
1fd5e000 | 655 | } |
84aeff41 CF |
656 | #ifdef DEBUGGING |
657 | void | |
658 | fork_init () | |
659 | { | |
84aeff41 CF |
660 | } |
661 | #endif /*DEBUGGING*/ | |
1fd5e000 CF |
662 | |
663 | #ifdef NEWVFORK | |
664 | /* Dummy function to force second assignment below to actually be | |
665 | carried out */ | |
666 | static vfork_save * | |
667 | get_vfork_val () | |
668 | { | |
669 | return vfork_storage.val (); | |
670 | } | |
671 | #endif | |
672 | ||
8dca9e23 | 673 | extern "C" int |
1fd5e000 CF |
674 | vfork () |
675 | { | |
676 | #ifndef NEWVFORK | |
9e1ad59d | 677 | debug_printf ("stub called"); |
1fd5e000 CF |
678 | return fork (); |
679 | #else | |
680 | vfork_save *vf = get_vfork_val (); | |
47026c07 | 681 | char **esp, **pp; |
1fd5e000 CF |
682 | |
683 | if (vf == NULL) | |
684 | vf = vfork_storage.create (); | |
25e40ae6 CF |
685 | else if (vf->pid) |
686 | return fork (); | |
1fd5e000 | 687 | |
9a4d574b CF |
688 | // FIXME the tls stuff could introduce a signal race if a child process |
689 | // exits quickly. | |
1fd5e000 CF |
690 | if (!setjmp (vf->j)) |
691 | { | |
692 | vf->pid = -1; | |
47026c07 | 693 | __asm__ volatile ("movl %%esp,%0": "=r" (vf->vfork_esp):); |
1fd5e000 | 694 | __asm__ volatile ("movl %%ebp,%0": "=r" (vf->vfork_ebp):); |
9a4d574b | 695 | for (pp = (char **) vf->frame, esp = vf->vfork_esp; |
9661a0c8 | 696 | esp <= vf->vfork_ebp + 2; pp++, esp++) |
47026c07 | 697 | *pp = *esp; |
8dca9e23 CF |
698 | vf->ctty = myself->ctty; |
699 | vf->sid = myself->sid; | |
700 | vf->pgid = myself->pgid; | |
e80cbe3e | 701 | cygheap->ctty_on_hold = cygheap->ctty; |
59297e04 CF |
702 | vf->console_count = cygheap->console_count; |
703 | debug_printf ("cygheap->ctty_on_hold %p, cygheap->console_count %d", cygheap->ctty_on_hold, cygheap->console_count); | |
12520587 CF |
704 | int res = cygheap->fdtab.vfork_child_dup () ? 0 : -1; |
705 | debug_printf ("%d = vfork()", res); | |
e431827c | 706 | _my_tls.call_signal_handler (); // FIXME: racy |
9a4d574b | 707 | vf->tls = _my_tls; |
12520587 | 708 | return res; |
1fd5e000 CF |
709 | } |
710 | ||
1fd5e000 | 711 | vf = get_vfork_val (); |
e2e07827 | 712 | |
9a4d574b | 713 | for (pp = (char **) vf->frame, esp = vf->vfork_esp; |
9661a0c8 | 714 | esp <= vf->vfork_ebp + 2; pp++, esp++) |
e2e07827 CF |
715 | *esp = *pp; |
716 | ||
9661a0c8 CF |
717 | cygheap->fdtab.vfork_parent_restore (); |
718 | ||
8dca9e23 CF |
719 | myself->ctty = vf->ctty; |
720 | myself->sid = vf->sid; | |
721 | myself->pgid = vf->pgid; | |
e80cbe3e | 722 | termios_printf ("cygheap->ctty %p, cygheap->ctty_on_hold %p", cygheap->ctty, cygheap->ctty_on_hold); |
59297e04 | 723 | cygheap->console_count = vf->console_count; |
8dca9e23 | 724 | |
1fd5e000 CF |
725 | if (vf->pid < 0) |
726 | { | |
8dca9e23 | 727 | int exitval = vf->exitval; |
5654f240 | 728 | vf->pid = 0; |
1fd5e000 CF |
729 | if ((vf->pid = fork ()) == 0) |
730 | exit (exitval); | |
731 | } | |
732 | ||
25e40ae6 CF |
733 | int pid = vf->pid; |
734 | vf->pid = 0; | |
8af0f81d | 735 | debug_printf ("exiting vfork, pid %d", pid); |
9661a0c8 | 736 | sig_dispatch_pending (); |
9a4d574b | 737 | |
e431827c | 738 | _my_tls.call_signal_handler (); // FIXME: racy |
9a4d574b | 739 | _my_tls = vf->tls; |
25e40ae6 | 740 | return pid; |
1fd5e000 CF |
741 | #endif |
742 | } | |
ce95c640 | 743 | |
ad02bb70 CF |
744 | /* Copy memory from one process to another. */ |
745 | ||
746 | bool | |
747 | child_copy (HANDLE hp, bool write, ...) | |
ce95c640 | 748 | { |
ad02bb70 CF |
749 | va_list args; |
750 | va_start (args, write); | |
751 | static const char *huh[] = {"read", "write"}; | |
752 | ||
753 | char *what; | |
754 | while ((what = va_arg (args, char *))) | |
755 | { | |
756 | char *low = va_arg (args, char *); | |
757 | char *high = va_arg (args, char *); | |
758 | DWORD todo = wincap.chunksize () ?: high - low; | |
759 | char *here; | |
760 | ||
761 | for (here = low; here < high; here += todo) | |
762 | { | |
763 | DWORD done = 0; | |
764 | if (here + todo > high) | |
765 | todo = high - here; | |
766 | int res; | |
767 | if (write) | |
768 | res = WriteProcessMemory (hp, here, here, todo, &done); | |
769 | else | |
770 | res = ReadProcessMemory (hp, here, here, todo, &done); | |
5d970405 | 771 | debug_printf ("%s - hp %p low %p, high %p, res %d", what, hp, low, high, res); |
ad02bb70 CF |
772 | if (!res || todo != done) |
773 | { | |
774 | if (!res) | |
775 | __seterrno (); | |
776 | /* If this happens then there is a bug in our fork | |
777 | implementation somewhere. */ | |
778 | system_printf ("%s %s copy failed, %p..%p, done %d, windows pid %u, %E", | |
0b7c56a5 | 779 | what, huh[write], low, high, done, myself->dwProcessId); |
ad02bb70 CF |
780 | goto err; |
781 | } | |
782 | } | |
783 | } | |
784 | ||
785 | debug_printf ("done"); | |
786 | return true; | |
787 | ||
788 | err: | |
789 | TerminateProcess (hp, 1); | |
790 | set_errno (EAGAIN); | |
791 | return false; | |
ce95c640 | 792 | } |