diff options
author | Christopher Faylor <me@cgf.cx> | 2011-11-14 05:29:49 +0400 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2011-11-14 05:29:49 +0400 |
commit | 56a197152621abcdd3d08b0f62daf5b734422860 (patch) | |
tree | 7a299853407aa265de302e498de8c31bb93742a5 /winsup/cygwin/pinfo.cc | |
parent | 46e7439b9dbed64e4d3388baf425486571593dec (diff) |
Throughout use "have_execed" macro rather than "hExeced" global handle.
Throughout rename _PROC_* to _CH_*.
* child_info.h: Include "pinfo.h".
(child_info_types): Rename _PROC_* -> _CH_* to avoid confusion with similarly
named constants.
(_PROC_*): Delete unneeded aliases.
(PROC_*): Ditto.
(CURR_CHILD_INFO_MAGIC): Ditto.
(cchildren): Define using "pinfo_minimal".
(child_info::set_saw_ctrl_c): Move to
(child_info_spawn::set_saw_ctrl_c): Here.
(child_info_spawn::lock): New field.
(child_info_spawn::hExeced): Ditto.
(child_info_spawn::ev): Ditto.
(child_info_spawn::~child_info_spawn): Move to sigproc.cc.
(child_info_spawn::child_info_spawn): Ditto.
(child_info_spawn::cleanup): Declare new function.
(child_info_spawn::set_saw_ctrl_c): Move to this class. Set flag only when
execed and return true when we have set the flag.
(child_info_spawn::child_info_spawn::signal_myself_exited): New function.
(child_info_spawn::wait_for_myself): Ditto.
(child_info_spawn::has_execed_cygwin): Ditto.
(child_info_spawn::has_execed): Ditto. Replaces "hExeced" test.
(child_info_spawn::operator HANDLE&): New operator.
(child_info_spawn::worker): Define old "spawn_guts" as class member.
(ch_spawn): Declare.
(have_execed): Define.
(have_execed_cygwin): Ditto.
* cygheap.h: Update comment.
* dcrt0.cc (get_cygwin_startup_info): Use _CH_* enums.
(child_info_spawn::handle_spawn): Ditto.
(dll_crt0_0): Ditto.
(multiple_cygwin_problem): Ditto.
* exceptions.cc (chExeced): Delete obsolete declaration.
(ctrl_c_handler): Reference set_saw_ctrl_c via new ch_spawn global.
* globals.cc (hExeced): Delete.
* pinfo.cc (pinfo::thisproc): Refer to cygheap as ::cygheap for consistency in
handle naming when -DDEBUGGING.
(pinfo::init): Accommodate case where myself.h is known but h0 is passed in.
(pinfo::pinfo): New constructor for setting up a pinfo passed in by previous
exec'or.
(pinfo::proc_waiter): Don't handle subprocess if we're in the process of
exiting due to an exec of a cygwin process. Don't close rd_proc_pipe here.
Close it when we actually are finished with the process. Use new
ch_spawn.signal_myself_exited function to let exec stub know that subprocess
has exited.
(pinfo::wait): Clarify debugging output.
(pinfo::release): Use "close_h" to close all handles to avoid races.
(winpids::add): Assume that elements of the array do not need to be zeroed and
are properly initialized or suffer problems on pinfo::release. Don't close
hProcess since release does that now.
* pinfo.h: Update comment.
(pinfo_minimal): Move some elements from pinfo here so that child_info_spawn
can use them.
(pinfo): Inherit from pinfo_minimal.
(pinfo::pinfo): Modify to accommodate new pinfo_minimal.
(pinfo::allow_remove): New function.
* sigproc.cc (proc_subproc): Use boolean values for true/false. Implement
PROC_EXEC_CLEANUP.
(proc_terminate): Set ppid = 1 since the procs list will only be iterated when
the process has not execed. Don't do any cleanup here since it is now handled
in pinfo::release.
(sigproc_init): Initialize sync_proc_subproc earlier.
(child_info::child_info): Assume that all important fields are properly
initialized and avoid memset().
(child_info_spawn::child_info_spawn): Specifically test for execing and then
set up appropriate fields in the struct.
(child_info_spawn::cleanup): Define new function.
(child_info_spawn::record_children): Specifically test for being execed here.
Fill in pinfo_minimal part of children array.
(child_info_spawn::reattach_children): Use constructor to duplicate information
for previous exec'or. Add more debugging output.
(remove_proc): Force deletion of thread when exiting due to exec. Rely on
pinfo::cleanup in release.
* sigproc.h (PROC_EXEC_CLEANUP): New enum.
(PROC_DETACHED_CHILD): Delete.
* spawn.cc (chExeced): Delete.
(child_info_spawn::worker): Rename from spawn_guts. Use elements of
child_info_spawn throughout rather than ch.whatever. Use ::cygheap to refer to
global rather than element of child_info. Use wait_for_myself() rather than
waitpid(). Call child_info_spawn::cleanup on function return.
(spawnve): Reflect movement of spawn_guts functionality into
child_info_spawn::worker.
* syscalls.cc (popen): Ditto.
* winsup.h (spawn_guts): Delete declaration.
Diffstat (limited to 'winsup/cygwin/pinfo.cc')
-rw-r--r-- | winsup/cygwin/pinfo.cc | 115 |
1 files changed, 77 insertions, 38 deletions
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index ea30293ba..52aac9349 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -77,10 +77,10 @@ pinfo::thisproc (HANDLE h) else if (!child_proc_info) /* child_proc_info is only set when this process was started by another cygwin process */ procinfo->start_time = time (NULL); /* Register our starting time. */ - else if (cygheap->pid_handle) + else if (::cygheap->pid_handle) { - ForceCloseHandle (cygheap->pid_handle); - cygheap->pid_handle = NULL; + ForceCloseHandle (::cygheap->pid_handle); + ::cygheap->pid_handle = NULL; } } @@ -215,6 +215,24 @@ pinfo::exit (DWORD n) } # undef self +inline void +pinfo::_pinfo_release () +{ + if (procinfo) + { + void *unmap_procinfo = procinfo; + procinfo = NULL; + UnmapViewOfFile (unmap_procinfo); + } + HANDLE close_h; + if (h) + { + close_h = h; + h = NULL; + ForceCloseHandle1 (close_h, pinfo_shared_handle); + } +} + void pinfo::init (pid_t n, DWORD flag, HANDLE h0) { @@ -233,7 +251,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0) DWORD access = FILE_MAP_READ | (flag & (PID_IN_USE | PID_EXECED | PID_MAP_RW) ? FILE_MAP_WRITE : 0); - if (!h0) + if (!h0 || myself.h) shloc = (flag & (PID_IN_USE | PID_EXECED)) ? SH_JUSTCREATE : SH_JUSTOPEN; else { @@ -331,7 +349,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0) break; loop: - release (); + _pinfo_release (); if (h0) yield (); } @@ -344,7 +362,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE h0) else { h = h0; - release (); + _pinfo_release (); } } @@ -365,6 +383,35 @@ pinfo::set_acl() debug_printf ("NtSetSecurityObject %p", status); } +pinfo::pinfo (HANDLE parent, pinfo_minimal& from, pid_t pid): + pinfo_minimal (), destroy (false), procinfo (NULL), waiter_ready (false), + wait_thread (NULL) +{ + HANDLE herr; + const char *duperr = NULL; + if (!DuplicateHandle (parent, herr = from.rd_proc_pipe, GetCurrentProcess (), + &rd_proc_pipe, 0, false, DUPLICATE_SAME_ACCESS)) + duperr = "couldn't duplicate parent rd_proc_pipe handle %p for forked child %d after exec, %E"; + else if (!DuplicateHandle (parent, herr = from.hProcess, GetCurrentProcess (), + &hProcess, 0, false, DUPLICATE_SAME_ACCESS)) + duperr = "couldn't duplicate parent process handle %p for forked child %d after exec, %E"; + else + { + h = NULL; + DuplicateHandle (parent, from.h, GetCurrentProcess (), &h, 0, false, + DUPLICATE_SAME_ACCESS); + init (pid, PID_MAP_RW, h); + if (*this) + return; + } + + if (duperr) + debug_printf (duperr, herr, pid); + + /* Returning with procinfo == NULL. Any open handles will be closed by the + destructor. */ +} + const char * _pinfo::_ctty (char *buf) { @@ -868,6 +915,7 @@ proc_waiter (void *arg) si.si_stime = pchildren[rc].rusage_self.ru_stime; #endif pid_t pid = vchild->pid; + bool its_me = vchild == myself; for (;;) { @@ -881,6 +929,9 @@ proc_waiter (void *arg) break; } + if (!its_me && have_execed_cygwin) + break; + si.si_uid = vchild->uid; switch (buf) @@ -889,8 +940,6 @@ proc_waiter (void *arg) continue; case 0: /* Child exited. Do some cleanup and signal myself. */ - CloseHandle (vchild.rd_proc_pipe); - vchild.rd_proc_pipe = NULL; vchild.maybe_set_exit_code_from_windows (); if (WIFEXITED (vchild->exitcode)) si.si_code = CLD_EXITED; @@ -918,15 +967,8 @@ proc_waiter (void *arg) continue; } - /* Special case: If the "child process" that died is us, then we're - execing. Just call proc_subproc directly and then exit this loop. - We're done here. */ - if (hExeced) - { - /* execing. no signals available now. */ - proc_subproc (PROC_CLEARWAIT, 0); - break; - } + if (its_me && ch_spawn.signal_myself_exited ()) + break; /* Send a SIGCHLD to myself. We do this here, rather than in proc_subproc to avoid the proc_subproc lock since the signal thread will eventually @@ -1003,13 +1045,13 @@ pinfo::wait () waiter_ready = false; /* Fire up a new thread to track the subprocess */ - cygthread *h = new cygthread (proc_waiter, this, "proc_waiter"); + cygthread *h = new cygthread (proc_waiter, this, "waitproc"); if (!h) sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid); else { wait_thread = h; - sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p", + sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_proc_pipe %p", (*this)->pid, (*this)->dwProcessId, rd_proc_pipe); } @@ -1036,7 +1078,7 @@ _pinfo::alert_parent (char sig) FIXME: Is there a race here if we run this while another thread is attempting to exec()? */ - if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || hExeced) + if (wr_proc_pipe == INVALID_HANDLE_VALUE || !myself->wr_proc_pipe || have_execed) /* no parent */; else { @@ -1059,17 +1101,19 @@ _pinfo::alert_parent (char sig) void pinfo::release () { - if (procinfo) + _pinfo_release (); + HANDLE close_h; + if (rd_proc_pipe) { - void *unmap_procinfo = procinfo; - procinfo = NULL; - UnmapViewOfFile (unmap_procinfo); + close_h = rd_proc_pipe; + rd_proc_pipe = NULL; + ForceCloseHandle1 (close_h, rd_proc_pipe); } - if (h) + if (hProcess) { - HANDLE close_h = h; - h = NULL; - ForceCloseHandle1 (close_h, pinfo_shared_handle); + close_h = hProcess; + hProcess = NULL; + ForceCloseHandle1 (close_h, childhProc); } } @@ -1145,15 +1189,15 @@ winpids::add (DWORD& nelem, bool winpid, DWORD pid) } pinfo& p = pinfolist[nelem]; + memset (&p, 0, sizeof (p)); - /* Open a the process to prevent a subsequent exit from invalidating the + /* Open a process to prevent a subsequent exit from invalidating the shared memory region. */ p.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, false, pid); _onreturn onreturn (p.hProcess); /* If we couldn't open the process then we don't have rights to it and should - make a copy of the shared memory area if it exists (it may not). - */ + make a copy of the shared memory area if it exists (it may not). */ bool perform_copy; if (!p.hProcess) perform_copy = true; @@ -1226,8 +1270,7 @@ out: else { *pnew = *p.procinfo; - if ((_pinfo *) p != (_pinfo *) myself) - p.release (); + p.release (); p.procinfo = pnew; p.destroy = false; } @@ -1344,11 +1387,7 @@ winpids::release () if (pinfolist[i] == (_pinfo *) myself) continue; else if (pinfolist[i].hProcess) - { - if (pinfolist[i]) - pinfolist[i].release (); - CloseHandle (pinfolist[i].hProcess); - } + pinfolist[i].release (); else if ((p = pinfolist[i])) { pinfolist[i].procinfo = NULL; |