* child_info.h (child_info_spawn::hexec_proc): Eliminate.
* dcrt0.cc (dll_crt0_0): Remove hexec_proc stuff. * fork.cc (fork_child): Remove call to pinfo_fixup_after_fork. * pinfo.cc (set_myself): Close and zero pid_handle if set. (pinfo_fixup_after_fork): Delete. (proc_waiter): Don't close vchild.hProcess here. Do that when we are remove the vchild from procs. Save hProcess as pid_handle only on first reparent operation. (pinfo::wait): Don't set pid_handle here. (pinfo::alert_parent): Always try to send signal. If unsuccessful then close and zero wr_proc_pipe. * pinfo.h (pinfo::pinfo): Make sure that appropriate parts of the class are zeroed on construction. (pinfo::alert_parent): Take char argument. (pinfo_fixup_after_fork): Delete declaration. (hexec_proc): Ditto. * sigproc.cc (remove_proc): Close pid_handle and hProcess if appropriate. * spawn.cc (spawn_guts): Set cygheap->pid_handle on first exec. * cygheap.h (init_cygheap::pid_handle): New element. * pinfo.cc (set_myself): Clear previously existing cygheap->pid_handle when a new process has been started. (pinfo::wait): Make sure that a handle to the newly forked/spawned process is kept around so that the pid will not be reused. * pinfo.h (_pinfo::pid_handle): Move. (pinfo::pid_handle): to here. * spawn.cc (spawn_guts): Create a pid_handle in cygheap prior to spawning to ensure that the pid does not get reused during the lifetime of the "cygwin pid". * pinfo.h (pinfo::alert_parent): New function. * exceptions.cc (sig_handle_tty_stop): Use alert_parent to send "signals" to parent. * fork.cc (fork_parent): Don't close pi.hProcess. Let the waiter thread do that. * pinfo.cc (proc_waiter): Detect case where process exits without setting the exit code and use value from GetExitCodeProcess. Reluctantly implement __SIGREPARENT. (pinfo::alert_parent): Define. * sigproc.h (__SIGREPARENT): New enum. * spawn.cc (spawn_guts): Send reparent signal to parent on exec. Always create process in suspended state to avoid races. Remove cygthread.h in favor of cygtls.h throughout since cygtls now includes cygthread.h. Eliminate ppid_handle usage throughout. * child_info.h: Regenerate magic number (child_info): Remove pppid_handle. * cygthread.h (cygthread::release): New method. Frees thread without waiting. * cygthread.cc (cygthread::stub): Set _ctinfo in _mytls to point to information for executing thread. Don't call SetEvent if thread is no longer in use. (cygthread::simplestub): Ditto. * cygtls.h (_cygtls::_ctinfo): New element contains pointer to information about executing cygthread, if any. * dcrt0.cc: Remove last vestiges of per_thread stuff. (dll_crt0_0): Ditto. Remove accommodation for ppid_handle. (do_exit): Remove obsolete reparenting test. (_exit): Exit with a more SUSv3-like exit value. * dtable.cc (dtable::stdio_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * exceptions.cc (open_stackdumpfile): Ditto. (handle_exceptions): Ditto. (ctrl_c_handler): Ditto. (sig_handle_tty_stop): Ditto. Let parent send signal to itself on STOP. (sigpacket::process): Comment out vfork test. (signal_exit): Use more SUSv3-like exit value on signal. * external.cc (fillout_pinfo): Don't set hProcess. * fork.cc: Remove VFORK cruft. (per_thread::set): Delete. (fork_child): Remove perthread stuff. (fork_parent): Remove obsolete subproc_init. Accommodate new method for tracking subprocesses. * pinfo.cc (set_myself): Accommodate new pinfo/_pinfo layout. Set some things here that used to be set in wait_sig. (_pinfo::exit): Set exitcode here. Close process pipe. (_pinfo::commune_send): Accommodeate new pinfo/_pinfo layout. (proc_waiter): New function. Waits, in a thread for subprocess to go away. (pinfo::wait): New function. Initialization for proc_waiter. * pinfo.h (_pinfo::exitcode): New element. (_pinfo::cygstarted): Ditto. (_pinfo::wr_proc_pipe): Ditto. (_pinfo::ppid_handle): Delete. (_pinfo::hProcess): Delete. (_pinfo::lock): Delete. (pinfo::hProcess): New element. (pinfo::lock): Ditto. (pinfo::wait): Declare new function. (pinfo::preserve): Define new function. * sigproc.cc: Remove old stuff from wait_subproc thread based method. (zombies): Remove. (procs): New. (my_parent_is_alive): Just check that the parent pid exists. (mychild): Just use pinfo methods to determine if child is mine. (proc_subproc): Revamp PROC_ADDCHILD to use pinfo::wait. Remove PROC_CHILDTERMINATED logic. Use different method to remove processes from list when SIGCHLD == SIG_IGN. (proc_terminate): Gut. (subproc_init): Delete. (init_child_info): Remove setting of pppid_handle. (checkstate): Revamp to only scan procs array. (remove_proc): Rename from remove_zombie. Don't close hProcess or pid_handle. Don't release memory if it's myself. (stopped_or_terminated): Change logic to handle new consolidated proc/zombie array. (wait_subproc): Delete. * sigproc.h: Remove obsolete EXIT_* defines. (subproc_init): Remove declaration. * spawn.cc (spawn_guts): Remove reparenting stuff. Use standard wait logic to wait for child if started from a non-cygwin process. * tlsoffsets.h: Regenerate. * tty.cc (tty_init): Check for myself->cygstarted rather than myself->ppid_handle to see if we were started by a cygwin process. * include/sys/signal.h (external_pinfo::exitcode): Replace hProcess. * include/sys/wait.h (WCOREDUMP): Define. * fhandler_tty.cc (fhandler_tty_slave::read): Add debugging output for timeout case. * signal.cc (abort): Flag that we are exiting with the ABORT signal.
This commit is contained in:
@@ -24,9 +24,9 @@ details. */
|
||||
#include "perprocess.h"
|
||||
#include "environ.h"
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <ntdef.h>
|
||||
#include "ntdll.h"
|
||||
#include "cygthread.h"
|
||||
#include "shared_info.h"
|
||||
#include "cygheap.h"
|
||||
#include "fhandler.h"
|
||||
@@ -37,23 +37,6 @@ static char NO_COPY pinfo_dummy[sizeof (_pinfo)] = {0};
|
||||
|
||||
pinfo NO_COPY myself ((_pinfo *)&pinfo_dummy); // Avoid myself != NULL checks
|
||||
|
||||
HANDLE hexec_proc;
|
||||
|
||||
void __stdcall
|
||||
pinfo_fixup_after_fork ()
|
||||
{
|
||||
if (hexec_proc)
|
||||
CloseHandle (hexec_proc);
|
||||
/* Keeps the cygpid from being reused. No rights required */
|
||||
if (!DuplicateHandle (hMainProc, hMainProc, hMainProc, &hexec_proc, 0,
|
||||
TRUE, 0))
|
||||
{
|
||||
system_printf ("couldn't save current process handle %p, %E", hMainProc);
|
||||
hexec_proc = NULL;
|
||||
}
|
||||
VerifyHandle (hexec_proc);
|
||||
}
|
||||
|
||||
/* Initialize the process table.
|
||||
This is done once when the dll is first loaded. */
|
||||
|
||||
@@ -70,7 +53,30 @@ set_myself (HANDLE h)
|
||||
if (!strace.active)
|
||||
strace.hello ();
|
||||
debug_printf ("myself->dwProcessId %u", myself->dwProcessId);
|
||||
InitializeCriticalSection (&myself->lock);
|
||||
InitializeCriticalSection (&myself.lock);
|
||||
myself->dwProcessId = GetCurrentProcessId ();
|
||||
if (h)
|
||||
{
|
||||
/* here if execed */
|
||||
static pinfo NO_COPY myself_identity;
|
||||
myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
|
||||
}
|
||||
else if (myself->ppid)
|
||||
{
|
||||
/* here if forked/spawned */
|
||||
pinfo parent (myself->ppid);
|
||||
/* We've inherited the parent's wr_proc_pipe. We don't need it,
|
||||
so close it. This could cause problems for the spawn case since there
|
||||
is no guarantee that a parent will still be around by the time we get
|
||||
here. If so, we would have a handle leak. FIXME? */
|
||||
if (parent && parent->wr_proc_pipe)
|
||||
CloseHandle (parent->wr_proc_pipe);
|
||||
if (cygheap->pid_handle)
|
||||
{
|
||||
ForceCloseHandle (cygheap->pid_handle);
|
||||
cygheap->pid_handle = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,17 +113,27 @@ _pinfo::exit (UINT n, bool norecord)
|
||||
exit_state = ES_FINAL;
|
||||
cygthread::terminate ();
|
||||
if (norecord)
|
||||
sigproc_terminate ();
|
||||
sigproc_terminate (); /* Just terminate signal and process stuff */
|
||||
else
|
||||
exitcode = n; /* We're really exiting. Record the UNIX exit code. */
|
||||
|
||||
if (this)
|
||||
{
|
||||
if (!norecord)
|
||||
process_state = PID_EXITED;
|
||||
|
||||
/* FIXME: There is a potential race between an execed process and its
|
||||
parent here. I hated to add a mutex just for this, though. */
|
||||
struct rusage r;
|
||||
fill_rusage (&r, hMainProc);
|
||||
add_rusage (&rusage_self, &r);
|
||||
|
||||
if (!norecord)
|
||||
{
|
||||
process_state = PID_EXITED;
|
||||
/* We could just let this happen automatically when the process
|
||||
exits but this should gain us a microsecond or so by notifying
|
||||
the parent early. */
|
||||
if (wr_proc_pipe)
|
||||
CloseHandle (wr_proc_pipe);
|
||||
}
|
||||
}
|
||||
|
||||
sigproc_printf ("Calling ExitProcess %d", n);
|
||||
@@ -259,6 +275,7 @@ pinfo::init (pid_t n, DWORD flag, HANDLE in_h)
|
||||
procinfo->process_state |= PID_IN_USE | PID_EXECED;
|
||||
procinfo->pid = myself->pid;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
destroy = 1;
|
||||
@@ -505,7 +522,7 @@ _pinfo::commune_send (DWORD code, ...)
|
||||
__seterrno ();
|
||||
goto err;
|
||||
}
|
||||
EnterCriticalSection (&myself->lock);
|
||||
EnterCriticalSection (&myself.lock);
|
||||
myself->tothem = tome;
|
||||
myself->fromthem = fromme;
|
||||
myself->hello_pid = pid;
|
||||
@@ -609,7 +626,7 @@ err:
|
||||
|
||||
out:
|
||||
myself->hello_pid = 0;
|
||||
LeaveCriticalSection (&myself->lock);
|
||||
LeaveCriticalSection (&myself.lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -642,6 +659,196 @@ _pinfo::cmdline (size_t& n)
|
||||
return s;
|
||||
}
|
||||
|
||||
/* This is the workhorse which waits for the write end of the pipe
|
||||
created during new process creation. If the pipe is closed, it is
|
||||
assumed that the cygwin pid has exited. Otherwise, various "signals"
|
||||
can be sent to the parent to inform the parent to perform a certain
|
||||
action.
|
||||
|
||||
This code was originally written to eliminate the need for "reparenting"
|
||||
but, unfortunately, reparenting is still needed in order to get the
|
||||
exit code of an execed windows process. Otherwise, the exit code of
|
||||
a cygwin process comes from the exitcode field in _pinfo. */
|
||||
static DWORD WINAPI
|
||||
proc_waiter (void *arg)
|
||||
{
|
||||
extern HANDLE hExeced;
|
||||
pinfo& vchild = *(pinfo *) arg;
|
||||
|
||||
siginfo_t si;
|
||||
si.si_signo = SIGCHLD;
|
||||
si.si_code = SI_KERNEL;
|
||||
si.si_pid = vchild->pid;
|
||||
si.si_errno = 0;
|
||||
#if 0 // FIXME: This is tricky to get right
|
||||
si.si_utime = pchildren[rc]->rusage_self.ru_utime;
|
||||
si.si_stime = pchildren[rc].rusage_self.ru_stime;
|
||||
#else
|
||||
si.si_utime = 0;
|
||||
si.si_stime = 0;
|
||||
#endif
|
||||
pid_t pid = vchild->pid;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
DWORD nb;
|
||||
char buf = '\0';
|
||||
if (!ReadFile (vchild.rd_proc_pipe, &buf, 1, &nb, NULL)
|
||||
&& GetLastError () != ERROR_BROKEN_PIPE)
|
||||
{
|
||||
system_printf ("error on read of child wait pipe %p, %E", vchild.rd_proc_pipe);
|
||||
break;
|
||||
}
|
||||
|
||||
si.si_uid = vchild->uid;
|
||||
|
||||
switch (buf)
|
||||
{
|
||||
case 0:
|
||||
/* Child exited. Do some cleanup and signal myself. */
|
||||
CloseHandle (vchild.rd_proc_pipe);
|
||||
vchild.rd_proc_pipe = NULL;
|
||||
|
||||
if (vchild->process_state != PID_EXITED && vchild.hProcess)
|
||||
{
|
||||
DWORD exit_code;
|
||||
if (GetExitCodeProcess (vchild.hProcess, &exit_code))
|
||||
vchild->exitcode = (exit_code & 0xff) << 8;
|
||||
}
|
||||
if (WIFEXITED (vchild->exitcode))
|
||||
si.si_sigval.sival_int = CLD_EXITED;
|
||||
else if (WCOREDUMP (vchild->exitcode))
|
||||
si.si_sigval.sival_int = CLD_DUMPED;
|
||||
else
|
||||
si.si_sigval.sival_int = CLD_KILLED;
|
||||
si.si_status = vchild->exitcode;
|
||||
vchild->process_state = PID_ZOMBIE;
|
||||
break;
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
case SIGSTOP:
|
||||
/* Child stopped. Signal myself. */
|
||||
si.si_sigval.sival_int = CLD_STOPPED;
|
||||
break;
|
||||
case SIGCONT:
|
||||
continue;
|
||||
case __SIGREPARENT: /* sigh */
|
||||
/* spawn_guts has signalled us that it has just started a new
|
||||
subprocess which will take over this cygwin pid. */
|
||||
|
||||
/* We need to keep a handle to the original windows process which
|
||||
represents the cygwin process around to make sure that the
|
||||
windows pid is not reused before we are through with it.
|
||||
So, detect the first time that a subprocess calls exec
|
||||
and save the current hprocess in the pid_handle field.
|
||||
On subsequent execs just close the handle. */
|
||||
if (!vchild.hProcess)
|
||||
/* something went wrong. oh well. */;
|
||||
else if (vchild.pid_handle)
|
||||
ForceCloseHandle1 (vchild.hProcess, childhProc);
|
||||
else
|
||||
vchild.pid_handle = vchild.hProcess;
|
||||
vchild.hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE,
|
||||
vchild->dwProcessId);
|
||||
vchild->cygstarted++;
|
||||
if (vchild.hProcess)
|
||||
ProtectHandle1 (vchild.hProcess, childhProc);
|
||||
continue;
|
||||
default:
|
||||
system_printf ("unknown value %d on proc pipe", buf);
|
||||
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 && vchild->pid == myself->pid)
|
||||
{
|
||||
/* execing. no signals available now. */
|
||||
proc_subproc (PROC_CLEARWAIT, 0);
|
||||
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
|
||||
be calling proc_subproc and could unnecessarily block. */
|
||||
sig_send (myself_nowait, si);
|
||||
|
||||
/* If we're just stopped or got a continue signal, keep looping.
|
||||
Otherwise, return this thread to the pool. */
|
||||
if (buf != '\0')
|
||||
sigproc_printf ("looping");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
sigproc_printf ("exiting wait thread for pid %d", pid);
|
||||
_my_tls._ctinfo->release (); /* return the cygthread to the cygthread pool */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* function to set up the process pipe and kick off proc_waiter */
|
||||
int
|
||||
pinfo::wait ()
|
||||
{
|
||||
HANDLE out;
|
||||
/* FIXME: execed processes should be able to wait for pids that were started
|
||||
by the process which execed them. */
|
||||
if (!CreatePipe (&rd_proc_pipe, &out, &sec_none_nih, 16))
|
||||
{
|
||||
system_printf ("Couldn't create pipe tracker for pid %d, %E",
|
||||
(*this)->pid);
|
||||
return 0;
|
||||
}
|
||||
/* Duplicate the write end of the pipe into the subprocess. Make it inheritable
|
||||
so that all of the execed children get it. */
|
||||
if (!DuplicateHandle (hMainProc, out, hProcess, &((*this)->wr_proc_pipe), 0,
|
||||
TRUE, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
system_printf ("Couldn't duplicate pipe topid %d(%p), %E", (*this)->pid,
|
||||
hProcess);
|
||||
return 0;
|
||||
}
|
||||
CloseHandle (out); /* Don't need this end in this proces */
|
||||
|
||||
preserve (); /* Preserve the shared memory associated with the pinfo */
|
||||
|
||||
/* Fire up a new thread to track the subprocess */
|
||||
cygthread *h = new cygthread (proc_waiter, this, "sig");
|
||||
if (!h)
|
||||
sigproc_printf ("tracking thread creation failed for pid %d", (*this)->pid);
|
||||
else
|
||||
{
|
||||
h->zap_h ();
|
||||
sigproc_printf ("created tracking thread for pid %d, winpid %p, rd_pipe %p",
|
||||
(*this)->pid, (*this)->dwProcessId, rd_proc_pipe);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* function to send a "signal" to the parent when something interesting happens
|
||||
in the child. */
|
||||
void
|
||||
pinfo::alert_parent (char sig)
|
||||
{
|
||||
DWORD nb;
|
||||
/* Send something to our parent. If the parent has gone away,
|
||||
close the pipe. */
|
||||
if (myself->wr_proc_pipe
|
||||
&& WriteFile (myself->wr_proc_pipe, &sig, 1, &nb, NULL))
|
||||
/* all is well */;
|
||||
else if (GetLastError () != ERROR_BROKEN_PIPE)
|
||||
debug_printf ("sending %d notification to parent failed, %E", sig);
|
||||
else
|
||||
{
|
||||
HANDLE closeit = myself->wr_proc_pipe;
|
||||
myself->wr_proc_pipe = NULL;
|
||||
CloseHandle (closeit);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pinfo::release ()
|
||||
{
|
||||
|
Reference in New Issue
Block a user