diff options
Diffstat (limited to 'winsup/cygwin/fork.cc')
-rw-r--r-- | winsup/cygwin/fork.cc | 116 |
1 files changed, 84 insertions, 32 deletions
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 22076fc1d..56ba0fc0f 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -47,6 +47,83 @@ class frok friend int fork (); }; +class lock_signals +{ + bool worked; +public: + lock_signals () + { + worked = sig_send (NULL, __SIGHOLD) == 0; + } + operator int () const + { + return worked; + } + void dont_bother () + { + worked = false; + } + ~lock_signals () + { + if (worked) + sig_send (NULL, __SIGNOHOLD); + } +}; + +class lock_pthread +{ + bool bother; +public: + lock_pthread (): bother (1) + { + pthread::atforkprepare (); + } + void dont_bother () + { + bother = false; + } + ~lock_pthread () + { + if (bother) + pthread::atforkparent (); + } +}; + +class hold_everything +{ +public: /* DELETEME*/ + bool& ischild; + /* Note the order of the locks below. It is important, + to avoid races, that the lock order be preserved. + + pthread is first because it serves as a master lock + against other forks being attempted while this one is active. + + signals is next to stop signal processing for the duration + of the fork. + + process is last. If it is put before signals, then a deadlock + could be introduced if the process attempts to exit due to a signal. */ + lock_pthread pthread; + lock_signals signals; + lock_process process; + +public: + hold_everything (bool& x): ischild (x) {} + operator int () const {return signals;} + + ~hold_everything() + { + if (ischild) + { + pthread.dont_bother (); + process.dont_bother (); + signals.dont_bother (); + } + } + +}; + static void resume_child (HANDLE forker_finished) { @@ -109,25 +186,6 @@ frok::error (const char *fmt, ...) return true; } -/* Set up a pipe which will track the life of a "pid" through - even after we've exec'ed. */ -void -child_info::prefork (bool detached) -{ - if (!detached) - { - if (!CreatePipe (&rd_proc_pipe, &wr_proc_pipe, &sec_none_nih, 16)) - api_fatal ("prefork: couldn't create pipe process tracker%E"); - - if (!SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT)) - api_fatal ("prefork: couldn't set process pipe(%p) inherit state, %E", - wr_proc_pipe); - ProtectHandle1 (rd_proc_pipe, rd_proc_pipe); - ProtectHandle1 (wr_proc_pipe, wr_proc_pipe); - } -} - int __stdcall frok::child (volatile char * volatile here) { @@ -213,10 +271,6 @@ frok::child (volatile char * volatile here) ld_preload (); fixup_hooks_after_fork (); _my_tls.fixup_after_fork (); - /* Clear this or the destructor will close them. In the case of - rd_proc_pipe that would be an invalid handle. In the case of - wr_proc_pipe it would be == my_wr_proc_pipe. Both would be bad. */ - ch.rd_proc_pipe = ch.wr_proc_pipe = NULL; cygwin_finished_initializing = true; return 0; } @@ -349,19 +403,18 @@ frok::parent (volatile char * volatile stack_here) cygheap->user.deimpersonate (); fix_impersonation = true; ch.refresh_cygheap (); - ch.prefork (); /* set up process tracking pipes. */ while (1) { hchild = NULL; - rc = CreateProcessW (myself->progname, /* image to run */ - myself->progname, /* what we send in arg0 */ + rc = CreateProcessW (myself->progname, /* image to run */ + myself->progname, /* what we send in arg0 */ &sec_none_nih, &sec_none_nih, - TRUE, /* inherit handles from parent */ + TRUE, /* inherit handles from parent */ c_flags, - NULL, /* environment filled in later */ - 0, /* use current drive/directory */ + NULL, /* environment filled in later */ + 0, /* use current drive/directory */ &si, &pi); @@ -393,8 +446,8 @@ frok::parent (volatile char * volatile stack_here) /* Wait for subproc to initialize itself. */ if (!ch.sync (pi.dwProcessId, hchild, FORK_WAIT_TIMEOUT)) { - if (!error ("forked process %u died unexpectedly, retry %d, exit code %d", - pi.dwProcessId, ch.retry, ch.exit_code)) + if (!error ("forked process died unexpectedly, retry %d, exit code %d", + ch.retry, ch.exit_code)) continue; this_errno = EAGAIN; goto cleanup; @@ -426,7 +479,6 @@ frok::parent (volatile char * volatile stack_here) /* Fill in fields in the child's process table entry. */ child->dwProcessId = pi.dwProcessId; child.hProcess = hchild; - ch.postfork (child); /* Hopefully, this will succeed. The alternative to doing things this way is to reserve space prior to calling CreateProcess and then fill |