From b79b15e9e3160ef31b8ace8f167a8e9647670647 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Wed, 26 Oct 2011 19:42:39 +0000 Subject: [PATCH] * child_info.h (cchildren): New struct. (child_info_spawn::nchildren): Rename from nprocs. (child_info_spawn::children): Change type to cchildren for more bookkeeping possibilities. (child_info_spawn::child_info_spawn): Clear nchildren. (child_info_spawn::record_children): Declare new function. (child_info_spawn::reattach_children): Ditto. * dcrt0.cc (child_info_spawn::handle_spawn): Call reattach_children to gather list of processes we are potentially waiting for. * pinfo.h (pinfo::pinfo): Make sure that rd_proc_pipe is always cleared. (pinfo::reattach): New function. * sigproc.cc: Move pinfo.h earlier so that it can be used in sigproc.h. (get_proc_lock): Don't bother with a lock during DLL initialization. (proc_subproc): Handle PROC_REATTACH_CHILD. (proc_terminate): Orphan children only when we are not an execed process or when the pid is about to be occupied by a non-cygwin process. (child_info_spawn::record_children): Define new function. (child_info_spawn::reattach_children): Ditto. * sigproc.h (procstuff): Define PROC_REATTACH_CHILD and renumber other elements. * spawn.cc (spawn_guts): Record any to-be-waited-for subprocesses if about to exec a cygwin process. * sigproc.cc (sig_send): Fix harmless transposition of fifth and six arguments to DuplicateHandle(). (child_info::child_info): Ditto. * globals.cc (hExeced): Make NO_COPY. --- winsup/cygwin/ChangeLog | 32 +++++++++++++++++++++++ winsup/cygwin/child_info.h | 16 +++++++++--- winsup/cygwin/dcrt0.cc | 6 +++++ winsup/cygwin/globals.cc | 2 +- winsup/cygwin/pinfo.cc | 28 ++++++++++++-------- winsup/cygwin/pinfo.h | 9 +++++-- winsup/cygwin/sigproc.cc | 52 ++++++++++++++++++++++++++++++++++---- winsup/cygwin/sigproc.h | 9 ++++--- winsup/cygwin/spawn.cc | 2 ++ 9 files changed, 129 insertions(+), 27 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 2e2c194d0..bf71c0d25 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,35 @@ +2011-10-25 Christopher Faylor + + * child_info.h (cchildren): New struct. + (child_info_spawn::nchildren): Rename from nprocs. + (child_info_spawn::children): Change type to cchildren for more + bookkeeping possibilities. + (child_info_spawn::child_info_spawn): Clear nchildren. + (child_info_spawn::record_children): Declare new function. + (child_info_spawn::reattach_children): Ditto. + * dcrt0.cc (child_info_spawn::handle_spawn): Call reattach_children to + gather list of processes we are potentially waiting for. + * pinfo.h (pinfo::pinfo): Make sure that rd_proc_pipe is always cleared. + (pinfo::reattach): New function. + * sigproc.cc: Move pinfo.h earlier so that it can be used in sigproc.h. + (get_proc_lock): Don't bother with a lock during DLL initialization. + (proc_subproc): Handle PROC_REATTACH_CHILD. + (proc_terminate): Orphan children only when we are not an execed + process or when the pid is about to be occupied by a non-cygwin + process. + (child_info_spawn::record_children): Define new function. + (child_info_spawn::reattach_children): Ditto. + * sigproc.h (procstuff): Define PROC_REATTACH_CHILD and renumber other + elements. + * spawn.cc (spawn_guts): Record any to-be-waited-for subprocesses if + about to exec a cygwin process. + + * sigproc.cc (sig_send): Fix harmless transposition of fifth and six + arguments to DuplicateHandle(). + (child_info::child_info): Ditto. + + * globals.cc (hExeced): Make NO_COPY. + 2011-10-25 Corinna Vinschen * hookapi.cc (hook_or_detect_cygwin): Take additional handle diff --git a/winsup/cygwin/child_info.h b/winsup/cygwin/child_info.h index ef7166f2d..95cb4d6eb 100644 --- a/winsup/cygwin/child_info.h +++ b/winsup/cygwin/child_info.h @@ -38,10 +38,16 @@ enum child_status #define EXEC_MAGIC_SIZE sizeof(child_info) /* Change this value if you get a message indicating that it is out-of-sync. */ -#define CURR_CHILD_INFO_MAGIC 0x29afd207U +#define CURR_CHILD_INFO_MAGIC 0xa049a83aU #define NPROCS 256 +struct cchildren +{ + pid_t pid; + HANDLE rd_proc_pipe; +}; + /* NOTE: Do not make gratuitous changes to the names or organization of the below class. The layout is checksummed to determine compatibility between different cygwin versions. */ @@ -56,8 +62,6 @@ public: HANDLE subproc_ready; // used for synchronization with parent HANDLE user_h; HANDLE parent; - int nprocs; - pid_t children[NPROCS]; init_cygheap *cygheap; void *cygheap_max; DWORD cygheap_reserve_sz; @@ -119,6 +123,8 @@ public: int __stdin; int __stdout; char filler[4]; + int nchildren; + cchildren children[NPROCS]; ~child_info_spawn () { @@ -135,8 +141,10 @@ public: cfree (moreinfo); } } - child_info_spawn (): moreinfo (NULL) {}; + child_info_spawn (): moreinfo (NULL), nchildren (0) {}; child_info_spawn (child_info_types, bool); + void record_children (); + void reattach_children (); void *operator new (size_t, void *p) __attribute__ ((nothrow)) {return p;} void set (child_info_types ci, bool b) { new (this) child_info_spawn (ci, b);} void handle_spawn () __attribute__ ((regparm (1))); diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index dd3ff021c..7c85f315a 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -625,6 +625,12 @@ child_info_spawn::handle_spawn () cygheap->fdtab.move_fd (__stdout, 1); cygheap->user.groups.clear_supp (); + /* If we're execing we may have "inherited" a list of children forked by the + previous process executing under this pid. Reattach them here so that we + can wait for them. */ + if (type == _PROC_EXEC) + reattach_children (); + ready (true); /* Need to do this after debug_fixup_after_fork_exec or DEBUGGING handling of diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index ae8cb5266..0b2ed573c 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -22,7 +22,7 @@ HANDLE NO_COPY hMainThread; HANDLE NO_COPY hProcToken; HANDLE NO_COPY hProcImpToken; HMODULE NO_COPY cygwin_hmodule; -HANDLE hExeced; +HANDLE NO_COPY hExeced; int NO_COPY sigExeced; WCHAR NO_COPY windows_system_directory[MAX_PATH]; UINT NO_COPY windows_system_directory_length; diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index 842b4275f..5a77d8f6c 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -971,19 +971,25 @@ _pinfo::dup_proc_pipe (HANDLE hProcess) int pinfo::wait () { - /* FIXME: execed processes should be able to wait for pids that were started - by the process which execed them. */ - if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16)) + /* If rd_proc_pipe that means we're in an execed process which already has + grabbed the read end of the pipe from the previous cygwin process running + with this pid. */ + if (!rd_proc_pipe) { - system_printf ("Couldn't create pipe tracker for pid %d, %E", - (*this)->pid); - return 0; - } + /* FIXME: execed processes should be able to wait for pids that were started + by the process which execed them. */ + if (!CreatePipe (&rd_proc_pipe, &((*this)->wr_proc_pipe), &sec_none_nih, 16)) + { + system_printf ("Couldn't create pipe tracker for pid %d, %E", + (*this)->pid); + return 0; + } - if (!(*this)->dup_proc_pipe (hProcess)) - { - system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess); - return 0; + if (!(*this)->dup_proc_pipe (hProcess)) + { + system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid, hProcess); + return 0; + } } preserve (); /* Preserve the shared memory associated with the pinfo */ diff --git a/winsup/cygwin/pinfo.h b/winsup/cygwin/pinfo.h index 746f99350..f9e859cde 100644 --- a/winsup/cygwin/pinfo.h +++ b/winsup/cygwin/pinfo.h @@ -147,8 +147,8 @@ public: bool waiter_ready; class cygthread *wait_thread; void init (pid_t, DWORD, HANDLE) __attribute__ ((regparm(3))); - pinfo (): procinfo (NULL) {} - pinfo (_pinfo *x): procinfo (x), hProcess (NULL) {} + pinfo (): procinfo (NULL), rd_proc_pipe (NULL) {} + pinfo (_pinfo *x): procinfo (x), rd_proc_pipe (NULL), hProcess (NULL) {} pinfo (pid_t n) : rd_proc_pipe (NULL), hProcess (NULL) {init (n, 0, NULL);} pinfo (pid_t n, DWORD flag) : rd_proc_pipe (NULL), hProcess (NULL), waiter_ready (0), wait_thread (NULL) {init (n, flag, NULL);} void thisproc (HANDLE) __attribute__ ((regparm (2))); @@ -175,6 +175,11 @@ public: #ifndef _SIGPROC_H int remember () {system_printf ("remember is not here"); return 0;} #else + void reattach () + { + proc_subproc (PROC_REATTACH_CHILD, (DWORD) this); + destroy = false; + } int remember (bool detach) { int res = proc_subproc (detach ? PROC_DETACHED_CHILD : PROC_ADDCHILD, diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 00a2c8af9..fc5f816f4 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -14,7 +14,6 @@ details. */ #include #include #include "cygerrno.h" -#include "pinfo.h" #include "path.h" #include "fhandler.h" #include "dtable.h" @@ -23,6 +22,7 @@ details. */ #include "shared_info.h" #include "cygtls.h" #include "sigproc.h" +#include "pinfo.h" #include "ntdll.h" /* @@ -129,6 +129,8 @@ signal_fixup_after_exec () static bool get_proc_lock (DWORD what, DWORD val) { + if (!cygwin_finished_initializing) + return true; Static int lastwhat = -1; if (!sync_proc_subproc) { @@ -234,6 +236,9 @@ proc_subproc (DWORD what, DWORD val) } if (what == PROC_DETACHED_CHILD) break; + /* fall through intentionally */ + + case PROC_REATTACH_CHILD: procs[nprocs] = vchild; rc = procs[nprocs].wait (); if (rc) @@ -379,6 +384,7 @@ proc_terminate () set to 1 so we don't do that either. if (!hExeced) */ + if (!hExeced || ISSTATE (myself, PID_NOTCYGWIN)) procs[i]->ppid = 1; if (procs[i].wait_thread) { @@ -596,8 +602,8 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) goto out; } VerifyHandle (hp); - if (!DuplicateHandle (hp, dupsig, GetCurrentProcess (), &sendsig, false, - 0, DUPLICATE_SAME_ACCESS) || !sendsig) + if (!DuplicateHandle (hp, dupsig, GetCurrentProcess (), &sendsig, 0, + false, DUPLICATE_SAME_ACCESS) || !sendsig) { __seterrno (); sigproc_printf ("DuplicateHandle failed, %E"); @@ -619,7 +625,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) __seterrno (); goto out; } - if (!DuplicateHandle (GetCurrentProcess (), tome, hp, &tome, false, 0, + if (!DuplicateHandle (GetCurrentProcess (), tome, hp, &tome, 0, false, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) { sigproc_printf ("DuplicateHandle for __SIGCOMMUNE failed, %E"); @@ -807,7 +813,7 @@ child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subpr allow the child to duplicate handles from the parent to itself. */ parent = NULL; if (!DuplicateHandle (GetCurrentProcess (), GetCurrentProcess (), - GetCurrentProcess (), &parent, 0, TRUE, + GetCurrentProcess (), &parent, 0, true, DUPLICATE_SAME_ACCESS)) system_printf ("couldn't create handle to myself for child, %E"); } @@ -830,6 +836,42 @@ child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_r { } +/* Record any non-reaped subprocesses to be passed to about-to-be-execed + process. FIXME: There is a race here if the process exits while we + are recording it. */ +void +child_info_spawn::record_children () +{ + /* FIXME: locking */ + for (nchildren = 0; nchildren < nprocs; nchildren++) + { + children[nchildren].pid = procs[nchildren]->pid; + children[nchildren].rd_proc_pipe = procs[nchildren].rd_proc_pipe; + } +} + +/* Reattach non-reaped subprocesses passed in from the cygwin process + which previously operated under this pid. FIXME: Is there a race here + if the process exits during cygwin's exec handoff? */ +void +child_info_spawn::reattach_children () +{ + for (int i = 0; i < nchildren; i++) + { + pinfo p (children[i].pid, PID_MAP_RW); + if (p) + { + if (!DuplicateHandle (parent, children[i].rd_proc_pipe, + GetCurrentProcess (), &p.rd_proc_pipe, 0, + false, DUPLICATE_SAME_ACCESS)) + system_printf ("couldn't duplicate parent %p handles for forked children after exec, %E", + children[i].rd_proc_pipe); + p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, p->pid); + p.reattach (); + } + } +} + void child_info::ready (bool execed) { diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index e0ea5e433..b63e5731a 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -34,10 +34,11 @@ enum enum procstuff { PROC_ADDCHILD = 1, // add a new subprocess to list - PROC_DETACHED_CHILD = 2, // set up a detached child - PROC_CLEARWAIT = 3, // clear all waits - signal arrived - PROC_WAIT = 4, // setup for wait() for subproc - PROC_NOTHING = 5 // nothing, really + PROC_REATTACH_CHILD = 2, // reattach after exec + PROC_DETACHED_CHILD = 3, // set up a detached child + PROC_CLEARWAIT = 4, // clear all waits - signal arrived + PROC_WAIT = 5, // setup for wait() for subproc + PROC_NOTHING = 6 // nothing, really }; struct sigpacket diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index f9e1504b1..490efd73c 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -546,6 +546,8 @@ spawn_guts (const char *prog_arg, const char *const *argv, ch.moreinfo = moreinfo; ch.__stdin = __stdin; ch.__stdout = __stdout; + if (mode == _P_OVERLAY && ch.iscygwin ()) + ch.record_children (); si.lpReserved2 = (LPBYTE) &ch; si.cbReserved2 = sizeof (ch);