]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fork.cc
* environ.cc (environ_init): Avoid a compiler warning.
[newlib-cygwin.git] / winsup / cygwin / fork.cc
CommitLineData
1fd5e000
CF
1/* fork.cc
2
ce006ffa 3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
1fd5e000
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
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
34static int npid;
35static int npid_max;
36static 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
48void
49per_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
59static void
60stack_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
78static int
79fork_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. */
129static int
130sync_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
185static int
9cec3d45 186resume_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 196static void __stdcall
c90e1cf1 197sync_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
230static int __stdcall
231fork_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
322static void
323slow_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 347static int __stdcall
20a2c443
CF
348fork_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
619extern "C" int
620fork ()
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
664void
665fork_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 */
680static vfork_save *
681get_vfork_val ()
682{
683 return vfork_storage.val ();
684}
685#endif
686
8dca9e23 687extern "C" int
1fd5e000
CF
688vfork ()
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}
This page took 0.192054 seconds and 5 git commands to generate.