]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fork.cc
Remove unneeded header files from source files throughout.
[newlib-cygwin.git] / winsup / cygwin / fork.cc
CommitLineData
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
6This file is part of Cygwin.
7
8This software is a copyrighted work licensed under the terms of the
9Cygwin license. Please consult the file "CYGWIN_LICENSE" for
10details. */
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
37class 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
50class lock_signals
51{
52 bool worked;
53public:
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
73class lock_pthread
74{
75 bool bother;
76public:
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
92class hold_everything
93{
e943a1a3 94public: /* 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
111public:
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 127static void
54dd79bb 128resume_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 136static void __stdcall
c90e1cf1 137sync_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 168int __stdcall
39fc0d36 169frok::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
260static void
261slow_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 286int __stdcall
39fc0d36 287frok::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
573cleanup:
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
588extern "C" int
589fork ()
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
657void
658fork_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 */
666static vfork_save *
667get_vfork_val ()
668{
669 return vfork_storage.val ();
670}
671#endif
672
8dca9e23 673extern "C" int
1fd5e000
CF
674vfork ()
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
746bool
747child_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}
This page took 0.397621 seconds and 5 git commands to generate.