* 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:
Christopher Faylor
2004-11-26 04:15:10 +00:00
parent c1ab3396dc
commit 8cb359d947
33 changed files with 656 additions and 798 deletions

View File

@ -28,10 +28,8 @@ details. */
#include "cygheap.h"
#include "child_info_magic.h"
#include "shared_info.h"
#include "cygthread.h"
#include "cygtls.h"
#include "sigproc.h"
#include "perthread.h"
#include "exceptions.h"
/*
@ -42,11 +40,9 @@ details. */
#define PSIZE 63 // Number of processes
#define wake_wait_subproc() SetEvent (events[0])
#define no_signals_available() (!hwait_sig || (myself->sendsig == INVALID_HANDLE_VALUE) || exit_state)
#define NZOMBIES 256
#define NPROCS 256
/*
* Global variables
@ -64,30 +60,15 @@ HANDLE NO_COPY signal_arrived; // Event signaled when a signal has
#define Static static NO_COPY
/* How long to wait for message/signals. Normally this is infinite.
On termination, however, these are set to zero as a flag to exit. */
Static DWORD proc_loop_wait = 1000; // Wait for subprocesses to exit
HANDLE NO_COPY sigCONT; // Used to "STOP" a process
Static cygthread *hwait_sig; // Handle of wait_sig thread
Static cygthread *hwait_subproc; // Handle of sig_subproc thread
Static HANDLE wait_sig_inited; // Control synchronization of
// message queue startup
/* Used by WaitForMultipleObjects. These are handles to child processes.
*/
Static HANDLE events[PSIZE + 1]; // All my children's handles++
#define hchildren (events + 1) // Where the children handles begin
Static int nchildren; // Number of active children
Static char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
Static int nzombies; // Number of deceased children
Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
#define pchildren ((pinfo *) cpchildren)
#define zombies ((pinfo *) czombies)
Static int nprocs; // Number of deceased children
Static char cprocs[(NPROCS + 1) * sizeof (pinfo)]; // All my deceased children info
#define procs ((pinfo *) cprocs)
Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
muto NO_COPY *sync_proc_subproc = NULL; // Control access to subproc stuff
@ -97,9 +78,8 @@ DWORD NO_COPY sigtid = 0; // ID of the signal thread
/* Function declarations */
static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
static __inline__ bool get_proc_lock (DWORD, DWORD);
static void __stdcall remove_zombie (int);
static int __stdcall stopped_or_terminated (waitq *, _pinfo *);
static DWORD WINAPI wait_subproc (VOID *);
static bool __stdcall remove_proc (int);
static bool __stdcall stopped_or_terminated (waitq *, _pinfo *);
static DWORD WINAPI wait_sig (VOID *arg);
/* wait_sig bookkeeping */
@ -152,33 +132,13 @@ bool __stdcall
my_parent_is_alive ()
{
bool res;
if (!myself->ppid_handle)
if (myself->cygstarted)
res = pid_exists (myself->ppid);
else
{
debug_printf ("No myself->ppid_handle");
debug_printf ("Not started by cygwin app");
res = false;
}
else
for (int i = 0; i < 2; i++)
switch (res = WaitForSingleObject (myself->ppid_handle, 0))
{
case WAIT_OBJECT_0:
debug_printf ("parent dead.");
res = false;
goto out;
case WAIT_TIMEOUT:
debug_printf ("parent still alive");
res = true;
goto out;
case WAIT_FAILED:
DWORD werr = GetLastError ();
if (werr == ERROR_INVALID_HANDLE && i == 0)
continue;
system_printf ("WFSO for myself->ppid_handle(%p) failed, error %d",
myself->ppid_handle, werr);
res = false;
goto out;
}
out:
return res;
}
@ -193,7 +153,7 @@ wait_for_sigthread ()
}
/* Get the sync_proc_subproc muto to control access to
* children, zombie arrays.
* children, proc arrays.
* Attempt to handle case where process is exiting as we try to grab
* the mutex.
*/
@ -260,16 +220,11 @@ proc_exists (_pinfo *p)
/* Return 1 if this is one of our children, zero otherwise.
FIXME: This really should be integrated with the rest of the proc_subproc
testing. Scanning these lists twice is inefficient. */
int __stdcall
bool __stdcall
mychild (int pid)
{
for (int i = 0; i < nchildren; i++)
if (pchildren[i]->pid == pid)
return 1;
for (int i = 0; i < nzombies; i++)
if (zombies[i]->pid == pid)
return 1;
return 0;
pinfo p (pid);
return p && p->ppid == myself->pid;
}
/* Handle all subprocess requests
@ -283,7 +238,6 @@ proc_subproc (DWORD what, DWORD val)
_pinfo *child;
int clearing;
waitq *w;
int thiszombie;
#define wval ((waitq *) val)
@ -301,84 +255,32 @@ proc_subproc (DWORD what, DWORD val)
* (usually called from the main thread)
*/
case PROC_ADDCHILD:
if (nchildren >= PSIZE - 1)
/* Filled up process table? */
if (nprocs >= NPROCS)
{
sigproc_printf ("proc table overflow: hit %d processes, pid %d\n",
nprocs, vchild->pid);
rc = 0;
set_errno (EMFILE); // FIXMENOW - what's the right errno?
break;
}
pchildren[nchildren] = vchild;
hchildren[nchildren] = vchild->hProcess;
if (!DuplicateHandle (hMainProc, vchild->hProcess, hMainProc, &vchild->pid_handle,
0, 0, DUPLICATE_SAME_ACCESS))
system_printf ("Couldn't duplicate child handle for pid %d, %E", vchild->pid);
ProtectHandle1 (vchild->pid_handle, pid_handle);
if (!DuplicateHandle (hMainProc, hMainProc, vchild->hProcess, &vchild->ppid_handle,
SYNCHRONIZE | PROCESS_DUP_HANDLE, TRUE, 0))
system_printf ("Couldn't duplicate my handle<%p> for pid %d, %E", hMainProc, vchild->pid);
vchild->ppid = myself->pid;
vchild->uid = myself->uid;
vchild->gid = myself->gid;
vchild->pgid = myself->pgid;
vchild->sid = myself->sid;
vchild->ctty = myself->ctty;
vchild->cygstarted = true;
vchild->process_state |= PID_INITIALIZING | (myself->process_state & PID_USETTY);
sigproc_printf ("added pid %d to wait list, slot %d, winpid %p, handle %p",
vchild->pid, nchildren, vchild->dwProcessId,
vchild->hProcess);
nchildren++;
wake_wait_subproc ();
break;
/* A child process had terminated.
Possibly this is just due to an exec(). Cygwin implements an exec()
as a "handoff" from one windows process to another. If child->hProcess
is different from what is recorded in hchildren, then this is an exec().
Otherwise this is a normal child termination event.
(called from wait_subproc thread) */
case PROC_CHILDTERMINATED:
if (hchildren[val] != pchildren[val]->hProcess)
procs[nprocs] = vchild;
rc = procs[nprocs].wait ();
if (rc)
{
sigproc_printf ("pid %d[%d], reparented old hProcess %p, new %p",
pchildren[val]->pid, val, hchildren[val], pchildren[val]->hProcess);
HANDLE h = hchildren[val];
hchildren[val] = pchildren[val]->hProcess; /* Filled out by child */
ForceCloseHandle1 (h, childhProc);
ProtectHandle1 (pchildren[val]->hProcess, childhProc);
rc = 0;
goto out; // This was an exec()
sigproc_printf ("added pid %d to proc table, slot %d", vchild->pid,
nprocs);
nprocs++;
}
sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
pchildren[val]->pid, val, hchildren[val], nchildren, nzombies);
thiszombie = nzombies;
zombies[nzombies] = pchildren[val]; // Add to zombie array
zombies[nzombies++]->process_state = PID_ZOMBIE;// Walking dead
sigproc_printf ("zombifying [%d], pid %d, handle %p, nchildren %d",
val, pchildren[val]->pid, hchildren[val], nchildren);
if ((int) val < --nchildren)
{
hchildren[val] = hchildren[nchildren];
pchildren[val] = pchildren[nchildren];
}
/* See if we should care about the this terminated process. If we've
filled up our table or if we're ignoring SIGCHLD, then we immediately
remove the process and move on. Otherwise, this process becomes a zombie
which must be reaped by a wait() call. FIXME: This is a very inelegant
way to deal with this and could lead to process hangs. */
if (nzombies >= NZOMBIES)
{
sigproc_printf ("zombie table overflow %d", thiszombie);
remove_zombie (thiszombie);
}
/* Don't scan the wait queue yet. Caller will send SIGCHLD to this process.
This will cause an eventual scan of waiters. */
break;
/* Handle a wait4() operation. Allocates an event for the calling
@ -401,8 +303,8 @@ proc_subproc (DWORD what, DWORD val)
*/
if ((wval->ev = wval->thread_ev) == NULL)
{
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
FALSE, NULL);
wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE, FALSE,
NULL);
ProtectHandle1 (wval->ev, wq_ev);
}
@ -459,9 +361,8 @@ proc_subproc (DWORD what, DWORD val)
}
if (global_sigs[SIGCHLD].sa_handler == (void *) SIG_IGN)
while (nzombies)
remove_zombie (0);
break;
for (int i = 0; i < nprocs; i += remove_proc (i))
continue;
}
out:
@ -492,54 +393,29 @@ _cygtls::remove_wq (DWORD wait)
* Called on process exit.
* Also called by spawn_guts to disassociate any subprocesses from this
* process. Subprocesses will then know to clean up after themselves and
* will not become zombies.
* will not become procs.
*/
void __stdcall
proc_terminate (void)
{
sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
sigproc_printf ("nprocs %d", nprocs);
/* Signal processing is assumed to be blocked in this routine. */
if (hwait_subproc)
if (nprocs)
{
proc_loop_wait = 0; // Tell wait_subproc thread to exit
sync_proc_subproc->acquire (WPSP);
wake_wait_subproc (); // Wake wait_subproc loop
hwait_subproc = NULL;
(void) proc_subproc (PROC_CLEARWAIT, 1);
/* Clean out zombie processes from the pid list. */
/* Clean out proc processes from the pid list. */
int i;
for (i = 0; i < nzombies; i++)
for (i = 0; i < nprocs; i++)
{
if (zombies[i]->hProcess)
{
ForceCloseHandle1 (zombies[i]->hProcess, childhProc);
ForceCloseHandle1 (zombies[i]->pid_handle, pid_handle);
}
zombies[i]->ppid = 1;
zombies[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
zombies[i].release (); // FIXME: this breaks older gccs for some reason
procs[i]->ppid = 1;
if (!proc_exists (procs[i]))
procs[i]->process_state = PID_EXITED; /* CGF FIXME - still needed? */
procs[i].release ();
}
/* Disassociate my subprocesses */
for (i = 0; i < nchildren; i++)
{
if (!pchildren[i]->hProcess)
sigproc_printf ("%d(%d) hProcess cleared already?", pchildren[i]->pid,
pchildren[i]->dwProcessId);
else
{
ForceCloseHandle1 (pchildren[i]->hProcess, childhProc);
sigproc_printf ("%d(%d) closed child handle", pchildren[i]->pid,
pchildren[i]->dwProcessId);
pchildren[i]->ppid = 1;
if (pchildren[i]->pgid == myself->pid)
pchildren[i]->process_state |= PID_ORPHANED;
}
pchildren[i].release ();
}
nchildren = nzombies = 0;
nprocs = 0;
sync_proc_subproc->release ();
}
sigproc_printf ("leaving");
@ -610,7 +486,7 @@ sigproc_init ()
ProtectHandle (wait_sig_inited);
/* sync_proc_subproc is used by proc_subproc. It serialises
* access to the children and zombie arrays.
* access to the children and proc arrays.
*/
new_muto (sync_proc_subproc);
@ -648,7 +524,7 @@ sigproc_terminate (void)
CloseHandle (sendsig);
}
}
proc_terminate (); // Terminate process handling thread
proc_terminate (); // clean up process stuff
return;
}
@ -833,25 +709,6 @@ out:
return rc;
}
/* Initialize the wait_subproc thread.
* Called from fork() or spawn() to initialize the handling of subprocesses.
*/
void __stdcall
subproc_init (void)
{
if (hwait_subproc)
return;
/* A "wakeup" handle which can be toggled to make wait_subproc reexamine
* the hchildren array.
*/
events[0] = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
hwait_subproc = new cygthread (wait_subproc, NULL, "proc");
hwait_subproc->zap_h ();
ProtectHandle (events[0]);
sigproc_printf ("started wait_subproc thread");
}
/* Initialize some of the memory block passed to child processes
by fork/spawn/exec. */
@ -864,7 +721,6 @@ init_child_info (DWORD chtype, child_info *ch, HANDLE subproc_ready)
ch->magic = CHILD_INFO_MAGIC;
ch->type = chtype;
ch->subproc_ready = subproc_ready;
ch->pppid_handle = myself->ppid_handle;
ch->fhandler_union_cb = sizeof (fhandler_union);
ch->user_h = cygwin_user_h;
}
@ -877,132 +733,107 @@ checkstate (waitq *parent_w)
{
int potential_match = 0;
sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
sigproc_printf ("nprocs %d", nprocs);
/* Check already dead processes first to see if they match the criteria
* given in w->next.
*/
for (int i = 0; i < nzombies; i++)
switch (stopped_or_terminated (parent_w, zombies[i]))
* given in w->next. */
int res;
for (int i = 0; i < nprocs; i++)
if ((res = stopped_or_terminated (parent_w, procs[i])))
{
case -1:
potential_match = -1;
break;
case 1:
remove_zombie (i);
remove_proc (i);
potential_match = 1;
goto out;
}
sigproc_printf ("checking alive children");
/* No dead terminated children matched. Check for stopped children. */
for (int i = 0; i < nchildren; i++)
switch (stopped_or_terminated (parent_w, pchildren[i]))
{
case -1:
potential_match = -1;
break;
case 1:
potential_match = 1;
goto out;
}
sigproc_printf ("no matching terminated children found");
potential_match = -!!nprocs;
out:
sigproc_printf ("returning %d", potential_match);
return potential_match;
}
/* Remove a zombie from zombies by swapping it with the last child in the list.
*/
static void __stdcall
remove_zombie (int ci)
/* Remove a proc from procs by swapping it with the last child in the list.
Also releases shared memory of exited processes. */
static bool __stdcall
remove_proc (int ci)
{
sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
nzombies);
if (proc_exists (procs[ci]))
return true;
if (zombies[ci])
sigproc_printf ("removing procs[%d], pid %d, nprocs %d", ci, procs[ci]->pid,
nprocs);
if (procs[ci] != myself)
{
ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
zombies[ci].release ();
procs[ci].release ();
if (procs[ci].pid_handle)
ForceCloseHandle1 (procs[ci].pid_handle, childhProc);
if (procs[ci].hProcess)
ForceCloseHandle1 (procs[ci].hProcess, childhProc);
}
if (ci < --nzombies)
zombies[ci] = zombies[nzombies];
return;
if (ci < --nprocs)
procs[ci] = procs[nprocs];
return 0;
}
/* Check status of child process vs. waitq member.
*
* parent_w is the pointer to the parent of the waitq member in question.
* child is the subprocess being considered.
*
* Returns
* 1 if stopped or terminated child matches parent_w->next criteria
* -1 if a non-stopped/terminated child matches parent_w->next criteria
* 0 if child does not match parent_w->next criteria
*/
static int __stdcall
parent_w is the pointer to the parent of the waitq member in question.
child is the subprocess being considered.
Returns non-zero if waiting thread released. */
static bool __stdcall
stopped_or_terminated (waitq *parent_w, _pinfo *child)
{
int potential_match;
int might_match;
waitq *w = parent_w->next;
sigproc_printf ("considering pid %d", child->pid);
if (w->pid == -1)
potential_match = 1;
might_match = 1;
else if (w->pid == 0)
potential_match = child->pgid == myself->pgid;
might_match = child->pgid == myself->pgid;
else if (w->pid < 0)
potential_match = child->pgid == -w->pid;
might_match = child->pgid == -w->pid;
else
potential_match = (w->pid == child->pid);
might_match = (w->pid == child->pid);
if (!potential_match)
if (!might_match)
return 0;
bool terminated;
int terminated;
if ((terminated = child->process_state == PID_ZOMBIE) ||
((w->options & WUNTRACED) && child->stopsig))
if (!((terminated = (child->process_state == PID_ZOMBIE)) ||
((w->options & WUNTRACED) && child->stopsig)))
return 0;
parent_w->next = w->next; /* successful wait. remove from wait queue */
w->pid = child->pid;
if (!terminated)
{
parent_w->next = w->next; /* successful wait. remove from wait queue */
w->pid = child->pid;
sigproc_printf ("stopped child");
w->status = (child->stopsig << 8) | 0x7f;
child->stopsig = 0;
}
else /* Should only get here when child has been moved to the procs array */
{
w->status = child->exitcode;
if (!terminated)
add_rusage (&myself->rusage_children, &child->rusage_children);
add_rusage (&myself->rusage_children, &child->rusage_self);
if (w->rusage)
{
sigproc_printf ("stopped child");
w->status = (child->stopsig << 8) | 0x7f;
child->stopsig = 0;
add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
}
else /* Should only get here when child has been moved to the zombies array */
{
DWORD status;
if (!GetExitCodeProcess (child->hProcess, &status))
status = 0xffff;
if (status & EXIT_SIGNAL)
w->status = (status >> 8) & 0xff; /* exited due to signal */
else
w->status = (status & 0xff) << 8; /* exited via "exit ()" */
add_rusage (&myself->rusage_children, &child->rusage_children);
add_rusage (&myself->rusage_children, &child->rusage_self);
if (w->rusage)
{
add_rusage ((struct rusage *) w->rusage, &child->rusage_children);
add_rusage ((struct rusage *) w->rusage, &child->rusage_self);
}
}
if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
system_printf ("couldn't wake up wait event %p, %E", w->ev);
return 1;
}
return -potential_match;
if (!SetEvent (w->ev)) /* wake up wait4 () immediately */
system_printf ("couldn't wake up wait event %p, %E", w->ev);
return true;
}
static void
@ -1078,27 +909,10 @@ wait_sig (VOID *self)
signals. Prior to this, dwProcessId was set to the windows pid of
of the original windows process which spawned us unless this was a
"toplevel" process. */
myself->dwProcessId = GetCurrentProcessId ();
myself->process_state |= PID_ACTIVE;
myself->process_state &= ~PID_INITIALIZING;
sigproc_printf ("myself->dwProcessId %u", myself->dwProcessId);
/* If we've been execed, then there is still a stub left in the previous
windows process waiting to see if it's started a cygwin process or not.
Signalling subproc_ready indicates that we are a cygwin process. */
if (child_proc_info && child_proc_info->type == PROC_EXEC)
{
debug_printf ("subproc_ready %p", child_proc_info->subproc_ready);
if (!SetEvent (child_proc_info->subproc_ready))
system_printf ("SetEvent (subproc_ready) failed, %E");
ForceCloseHandle1 (child_proc_info->subproc_ready, subproc_ready);
/* Initialize an "indirect" pid block so that if someone looks up this
process via its Windows PID it will be redirected to the appropriate
Cygwin PID shared memory block. */
static pinfo NO_COPY myself_identity;
myself_identity.init (cygwin_pid (myself->dwProcessId), PID_EXECED);
}
SetEvent (wait_sig_inited);
sigtid = GetCurrentThreadId ();
@ -1215,85 +1029,3 @@ wait_sig (VOID *self)
sigproc_printf ("done");
ExitThread (0);
}
/* Wait for subprocesses to terminate. Executes in a separate thread. */
static DWORD WINAPI
wait_subproc (VOID *)
{
sigproc_printf ("starting");
int errloop = 0;
for (;;)
{
DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE,
proc_loop_wait);
if (!proc_loop_wait)
break;
if (rc == WAIT_TIMEOUT)
continue;
if (rc == WAIT_FAILED)
{
/* It's ok to get an ERROR_INVALID_HANDLE since another thread may have
closed a handle in the children[] array. So, we try looping a couple
of times to stabilize. FIXME - this is not foolproof. Probably, this
thread should be responsible for closing the children. */
if (!errloop++)
proc_subproc (PROC_NOTHING, 0); // Just synchronize and continue
if (errloop < 10)
continue;
system_printf ("wait failed. nchildren %d, wait %d, %E",
nchildren, proc_loop_wait);
for (int i = 0; i <= nchildren; i++)
if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 ||
rc == WAIT_TIMEOUT)
continue;
else if (i == 0)
system_printf ("nchildren %d, event[%d] %p, %E", nchildren, i, events[i]);
else
{
system_printf ("nchildren %d, event[%d] %p, pchildren[%d] %p, events[0] %p, %E",
nchildren, i, events[i], i - 1, (_pinfo *) pchildren[i - 1], events[0]);
system_printf ("pid %d, dwProcessId %u, hProcess %p, progname '%s'",
pchildren[i - 1]->pid, pchildren[i - 1]->dwProcessId,
pchildren[i - 1]->hProcess, pchildren[i - 1]->progname);
}
break;
}
errloop = 0;
rc -= WAIT_OBJECT_0;
if (rc-- != 0)
{
siginfo_t si;
si.si_signo = SIGCHLD;
si.si_code = SI_KERNEL;
si.si_pid = pchildren[rc]->pid;
si.si_uid = pchildren[rc]->uid;
si.si_errno = 0;
GetExitCodeProcess (hchildren[rc], (DWORD *) &si.si_status);
#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
rc = proc_subproc (PROC_CHILDTERMINATED, rc);
/* 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. */
if (rc)
sig_send (myself_nowait, si);
}
sigproc_printf ("looping");
}
ForceCloseHandle (events[0]);
events[0] = NULL;
sigproc_printf ("done");
ExitThread (0);
}