* debug.cc (threadname_init): Pass name of lock as arg 2 of new_muto. * malloc.cc (malloc_init): Ditto. * sigproc.cc (sigproc_init): Ditto. * exceptions.cc (events_init): Ditto. (call_handler): Eliminate special case for hExeced. Report locked thread in debugging output. * fhandler.cc (fhandker_pipe::fhandler_pipe): Propagate device type to base class. * fhandler.h (fhandler_pipe): Ditto. * hinfo.cc (hinfo::build_fhandler): Pass specific type of pipe to constructor. * spawn.cc (spawn_guts): Eliminate dependency on signal when waiting for subprocess. * strace.cc: Remove obsolete #ifdef. * sync.cc (muto::muto): Save the name of the muto. (muto:~muto): Also release the muto. * sync.h: Add a muto name field. * select.cc (peek_pipe): Avoid doing a PeekNamedPipe on the write end of a pipe.
		
			
				
	
	
		
			1367 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1367 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* sigproc.cc: inter/intra signal and sub process handler
 | 
						|
 | 
						|
   Copyright 1997, 1998, 1999, 2000 Cygnus Solutions.
 | 
						|
 | 
						|
   Written by Christopher Faylor <cgf@cygnus.com>
 | 
						|
 | 
						|
This file is part of Cygwin.
 | 
						|
 | 
						|
This software is a copyrighted work licensed under the terms of the
 | 
						|
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | 
						|
details. */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <time.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include "winsup.h"
 | 
						|
#include "sync.h"
 | 
						|
 | 
						|
extern BOOL allow_ntsec;
 | 
						|
 | 
						|
/*
 | 
						|
 * Convenience defines
 | 
						|
 */
 | 
						|
#define WSSC		   60000 // Wait for signal completion
 | 
						|
#define WPSP		   40000 // Wait for proc_subproc mutex
 | 
						|
#define WSPX		   20000 // Wait for wait_sig to terminate
 | 
						|
#define WWSP		   20000 // Wait for wait_subproc to terminate
 | 
						|
 | 
						|
#define WAIT_SIG_PRIORITY		THREAD_PRIORITY_NORMAL
 | 
						|
 | 
						|
#define TOTSIGS	(NSIG + __SIGOFFSET)
 | 
						|
 | 
						|
#define sip_printf(fmt, args...) sigproc_printf (fmt , ## args)
 | 
						|
 | 
						|
#define wake_wait_subproc() SetEvent (events[0])
 | 
						|
 | 
						|
#define no_signals_available() (!hwait_sig || !sig_loop_wait)
 | 
						|
 | 
						|
/*
 | 
						|
 * Global variables
 | 
						|
 */
 | 
						|
const char *__sp_fn ;
 | 
						|
int __sp_ln;
 | 
						|
 | 
						|
char NO_COPY myself_nowait_dummy[1] = {'0'};// Flag to sig_send that signal goes to
 | 
						|
					//  current process but no wait is required
 | 
						|
char NO_COPY myself_nowait_nonmain_dummy[1] = {'1'};// Flag to sig_send that signal goes to
 | 
						|
					//  current process but no wait is required
 | 
						|
					//  if this is not the main thread.
 | 
						|
 | 
						|
HANDLE NO_COPY signal_arrived;		// Event signaled when a signal has
 | 
						|
					//  resulted in a user-specified
 | 
						|
					//  function call
 | 
						|
/*
 | 
						|
 * Common variables
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
/* How long to wait for message/signals.  Normally this is infinite.
 | 
						|
 * On termination, however, these are set to zero as a flag to exit.
 | 
						|
 */
 | 
						|
 | 
						|
#define Static static NO_COPY
 | 
						|
 | 
						|
Static DWORD proc_loop_wait = 500;	// Wait for subprocesses to exit
 | 
						|
Static DWORD sig_loop_wait = 500;	// Wait for signals to arrive
 | 
						|
 | 
						|
Static HANDLE sigcatch_nonmain = NULL;	// The semaphore signaled when
 | 
						|
					//  signals are available for
 | 
						|
					//  processing from non-main thread
 | 
						|
Static HANDLE sigcatch_main = NULL;	// Signalled when main thread sends a
 | 
						|
					//  signal
 | 
						|
Static HANDLE sigcatch_nosync = NULL;	// Signal wait_sig to scan sigtodo
 | 
						|
					//  but not to bother with any
 | 
						|
					//  synchronization
 | 
						|
Static HANDLE sigcomplete_main = NULL;	// Event signaled when a signal has
 | 
						|
					//  finished processing for the main
 | 
						|
					//  thread
 | 
						|
Static HANDLE sigcomplete_nonmain = NULL;// Semaphore raised for non-main
 | 
						|
					//  threads when a signal has finished
 | 
						|
					//  processing
 | 
						|
Static HANDLE hwait_sig = NULL;		// Handle of wait_sig thread
 | 
						|
Static HANDLE hwait_subproc = NULL;	// Handle of sig_subproc thread
 | 
						|
 | 
						|
Static HANDLE wait_sig_inited = NULL;	// Control synchronization of
 | 
						|
					//  message queue startup
 | 
						|
 | 
						|
/* Used by WaitForMultipleObjects.  These are handles to child processes.
 | 
						|
 */
 | 
						|
Static HANDLE events[PSIZE + 1] = {0};	// All my children's handles++
 | 
						|
#define hchildren (events + 1)		// Where the children handles begin
 | 
						|
Static pinfo *pchildren[PSIZE] = {NULL};// All my children info
 | 
						|
Static pinfo *zombies[PSIZE] = {NULL};	// All my deceased children info
 | 
						|
Static int nchildren = 0;		// Number of active children
 | 
						|
Static int nzombies = 0;		// Number of deceased children
 | 
						|
 | 
						|
Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
 | 
						|
Static waitq waitq_main;		// Storage for main thread
 | 
						|
 | 
						|
muto NO_COPY *sync_proc_subproc = NULL;	// Control access to subproc stuff
 | 
						|
 | 
						|
DWORD NO_COPY maintid = 0;		// ID of the main thread
 | 
						|
DWORD NO_COPY sigtid = 0;		// ID of the signal thread
 | 
						|
 | 
						|
int NO_COPY pending_signals = 0;	// TRUE if signals pending
 | 
						|
 | 
						|
/* Functions
 | 
						|
 */
 | 
						|
static int __stdcall checkstate (waitq *);
 | 
						|
static __inline__ BOOL get_proc_lock (DWORD, DWORD);
 | 
						|
static HANDLE __stdcall getsem (pinfo *, const char *, int, int);
 | 
						|
static void __stdcall remove_child (int);
 | 
						|
static void __stdcall remove_zombie (int);
 | 
						|
static DWORD WINAPI wait_sig (VOID *arg);
 | 
						|
static int __stdcall stopped_or_terminated (waitq *, pinfo *);
 | 
						|
static DWORD WINAPI wait_subproc (VOID *);
 | 
						|
 | 
						|
/* Determine if the parent process is alive.
 | 
						|
 */
 | 
						|
 | 
						|
BOOL __stdcall
 | 
						|
my_parent_is_alive ()
 | 
						|
{
 | 
						|
  DWORD res;
 | 
						|
  if (!parent_alive)
 | 
						|
    {
 | 
						|
      debug_printf ("No parent_alive mutex");
 | 
						|
      res = FALSE;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    for (int i = 0; i < 2; i++)
 | 
						|
      switch (res = WaitForSingleObject (parent_alive, 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 parent_alive(%p) failed, error %d",
 | 
						|
			   parent_alive, werr);
 | 
						|
	    res = FALSE;
 | 
						|
	    goto out;
 | 
						|
	}
 | 
						|
out:
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
__inline static void
 | 
						|
wait_for_me ()
 | 
						|
{
 | 
						|
  /* See if this is the first signal call after initialization.
 | 
						|
   * If so, wait for notification that all initialization has completed.
 | 
						|
   * Then set the handle to NULL to avoid checking this again.
 | 
						|
   */
 | 
						|
  if (wait_sig_inited)
 | 
						|
    {
 | 
						|
      (void) WaitForSingleObject (wait_sig_inited, INFINITE);
 | 
						|
      (void) ForceCloseHandle (wait_sig_inited);
 | 
						|
      wait_sig_inited = NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static BOOL __stdcall
 | 
						|
proc_can_be_signalled (pinfo *p)
 | 
						|
{
 | 
						|
  if (p == myself_nowait || p == myself_nowait_nonmain || p == myself)
 | 
						|
    {
 | 
						|
      wait_for_me ();
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
  return ISSTATE (p, PID_INITIALIZING) ||
 | 
						|
	 (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) ==
 | 
						|
	  (PID_ACTIVE | PID_IN_USE));
 | 
						|
}
 | 
						|
 | 
						|
/* Test to determine if a process really exists and is processing
 | 
						|
 * signals.
 | 
						|
 */
 | 
						|
BOOL __stdcall
 | 
						|
proc_exists (pinfo *p)
 | 
						|
{
 | 
						|
  HANDLE h;
 | 
						|
 | 
						|
  if (p == NULL)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  if (p == myself || p == myself_nowait_nonmain || p == myself_nowait)
 | 
						|
    return TRUE;
 | 
						|
 | 
						|
  if (p->process_state == PID_NOT_IN_USE || !p->dwProcessId)
 | 
						|
    return FALSE;
 | 
						|
 | 
						|
  sip_printf ("checking for existence of pid %d, window pid %d", p->pid,
 | 
						|
	      p->dwProcessId);
 | 
						|
  if (p->ppid == myself->pid && p->hProcess != NULL)
 | 
						|
    {
 | 
						|
      sip_printf ("it's mine, process_state %x", p->process_state);
 | 
						|
      return proc_can_be_signalled (p);
 | 
						|
    }
 | 
						|
 | 
						|
  /* Note: Process is alive if OpenProcess() call fails due to permissions */
 | 
						|
  if (((h = OpenProcess (STANDARD_RIGHTS_REQUIRED, FALSE, p->dwProcessId))
 | 
						|
      != NULL) || (GetLastError () == ERROR_ACCESS_DENIED))
 | 
						|
    {
 | 
						|
      sip_printf ("it exists, %p", h);
 | 
						|
      if (h)
 | 
						|
	{
 | 
						|
	  DWORD rc = WaitForSingleObject (h, 0);
 | 
						|
	  CloseHandle (h);
 | 
						|
	  if (rc == WAIT_OBJECT_0)
 | 
						|
	    return 0;
 | 
						|
	}
 | 
						|
      return proc_can_be_signalled (p);
 | 
						|
    }
 | 
						|
 | 
						|
  sip_printf ("it doesn't exist");
 | 
						|
  /* If the parent pid does not exist, clean this process out of the pinfo
 | 
						|
   * table.  It must have died abnormally.
 | 
						|
   */
 | 
						|
  if ((p->pid == p->ppid) || (p->ppid == 1) || !proc_exists (procinfo (p->ppid)))
 | 
						|
    {
 | 
						|
      p->hProcess = NULL;
 | 
						|
      p->process_state = PID_NOT_IN_USE;
 | 
						|
    }
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/* Handle all subprocess requests
 | 
						|
 */
 | 
						|
#define vchild ((pinfo *) val)
 | 
						|
int __stdcall
 | 
						|
proc_subproc (DWORD what, DWORD val)
 | 
						|
{
 | 
						|
  int rc = 1;
 | 
						|
  int potential_match;
 | 
						|
  DWORD exitcode;
 | 
						|
  pinfo *child;
 | 
						|
  int clearing;
 | 
						|
  waitq *w;
 | 
						|
 | 
						|
#define wval	 ((waitq *) val)
 | 
						|
 | 
						|
  sip_printf ("args: %x, %d", what, val);
 | 
						|
 | 
						|
  if (!get_proc_lock (what, val))	// Serialize access to this function
 | 
						|
    {
 | 
						|
      sip_printf ("I am not ready");
 | 
						|
      goto out1;
 | 
						|
    }
 | 
						|
 | 
						|
  switch (what)
 | 
						|
    {
 | 
						|
    /* Add a new subprocess to the children arrays.
 | 
						|
     * (usually called from the main thread)
 | 
						|
     */
 | 
						|
    case PROC_ADDCHILD:
 | 
						|
      if (nchildren >= PSIZE - 1)
 | 
						|
	system_printf ("nchildren too large %d", nchildren);
 | 
						|
      if (WaitForSingleObject (vchild->hProcess, 0) != WAIT_TIMEOUT)
 | 
						|
	{
 | 
						|
	  system_printf ("invalid process handle %p.  pid %d, win pid %d",
 | 
						|
			vchild->hProcess, vchild->pid, vchild->dwProcessId);
 | 
						|
	  rc = 0;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      pchildren[nchildren] = vchild;
 | 
						|
      hchildren[nchildren] = vchild->hProcess;
 | 
						|
      ProtectHandle (vchild->hProcess);
 | 
						|
      sip_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:
 | 
						|
      rc = 0;
 | 
						|
      child = pchildren[val];
 | 
						|
      if (GetExitCodeProcess (hchildren[val], &exitcode) &&
 | 
						|
	  hchildren[val] != child->hProcess)
 | 
						|
	{
 | 
						|
	  sip_printf ("pid %d[%d], reparented old hProcess %p, new %p",
 | 
						|
		      child->pid, val, hchildren[val], child->hProcess);
 | 
						|
	  ForceCloseHandle1 (hchildren[val], childhProc);
 | 
						|
	  hchildren[val] = child->hProcess; /* Filled out by child */
 | 
						|
	  ProtectHandle1 (child->hProcess, childhProc);
 | 
						|
	  break;			// This was an exec()
 | 
						|
	}
 | 
						|
 | 
						|
      sip_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
 | 
						|
		  child->pid, val, hchildren[val], nchildren, nzombies);
 | 
						|
      remove_child (val);		// Remove from children arrays
 | 
						|
      zombies[nzombies++] = child;	// Add to zombie array
 | 
						|
      child->process_state = PID_ZOMBIE;// Walking dead
 | 
						|
      if (!proc_loop_wait)		// Don't bother if wait_subproc is
 | 
						|
	break;				//  exiting
 | 
						|
 | 
						|
      /* Send a SIGCHLD to myself. */
 | 
						|
      rc = sig_send (myself_nowait, SIGCHLD);	// Send a SIGCHLD
 | 
						|
      break;
 | 
						|
 | 
						|
    /* A child is in the stopped state.  Scan wait() queue to see if anyone
 | 
						|
     * should be notified.  (Called from wait_sig thread)
 | 
						|
     */
 | 
						|
    case PROC_CHILDSTOPPED:
 | 
						|
      child = myself;		// Just to avoid accidental NULL dereference
 | 
						|
      sip_printf ("Received stopped notification");
 | 
						|
      clearing = 0;
 | 
						|
      goto scan_wait;
 | 
						|
 | 
						|
    /* Clear all waiting threads.  Called from exceptions.cc prior to
 | 
						|
     * the main thread's dispatch to a signal handler function.
 | 
						|
     * (called from wait_sig thread)
 | 
						|
     */
 | 
						|
    case PROC_CLEARWAIT:
 | 
						|
      /* Clear all "wait"ing threads. */
 | 
						|
      if (val)
 | 
						|
	sip_printf ("clear waiting threads");
 | 
						|
      else
 | 
						|
	sip_printf ("looking for processes to reap");
 | 
						|
      clearing = val;
 | 
						|
 | 
						|
    scan_wait:
 | 
						|
      /* Scan the linked list of wait()ing threads.  If a wait's parameters
 | 
						|
       * match this pid, then activate it.
 | 
						|
       */
 | 
						|
      for (w = &waitq_head; w->next != NULL; w = w->next)
 | 
						|
	{
 | 
						|
	  if ((potential_match = checkstate (w)) > 0)
 | 
						|
	    sip_printf ("released waiting thread");
 | 
						|
	  else if (!clearing && potential_match < 0)
 | 
						|
	    sip_printf ("only found non-terminated children");
 | 
						|
	  else if (potential_match <= 0)		// nothing matched
 | 
						|
	    {
 | 
						|
	      sip_printf ("waiting thread found no children");
 | 
						|
	      HANDLE oldw = w->next->ev;
 | 
						|
	      if (clearing)
 | 
						|
		w->next->status = -1;		/* flag that a signal was received */
 | 
						|
	      else
 | 
						|
		w->next->ev = NULL;
 | 
						|
	      if (!SetEvent (oldw))
 | 
						|
		system_printf ("couldn't wake up wait event %p, %E", oldw);
 | 
						|
	      w->next = w->next->next;
 | 
						|
	    }
 | 
						|
	  if (w->next == NULL)
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
 | 
						|
      if (!clearing)
 | 
						|
	sip_printf ("finished processing terminated/stopped child");
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  waitq_head.next = NULL;
 | 
						|
	  sip_printf ("finished clearing");
 | 
						|
	}
 | 
						|
      break;
 | 
						|
 | 
						|
    /* Handle a wait4() operation.  Allocates an event for the calling
 | 
						|
     * thread which is signaled when the appropriate pid exits or stops.
 | 
						|
     * (usually called from the main thread)
 | 
						|
     */
 | 
						|
    case PROC_WAIT:
 | 
						|
      wval->ev = NULL;		// Don't know event flag yet
 | 
						|
 | 
						|
      if (wval->pid <= 0)
 | 
						|
	child = NULL;		// Not looking for a specific pid
 | 
						|
      else if ((child = procinfo (wval->pid)) == NULL)
 | 
						|
	goto out;		// invalid pid.  flag no such child
 | 
						|
 | 
						|
      wval->status = 0;		// Don't know status yet
 | 
						|
 | 
						|
      /* Put waitq structure at the end of a linked list. */
 | 
						|
      for (w = &waitq_head; w->next != NULL; w = w->next)
 | 
						|
	if (w->next == wval && (w->next = w->next->next) == NULL)
 | 
						|
	  break;
 | 
						|
 | 
						|
      wval->next = NULL;	/* This will be last in the list */
 | 
						|
      sip_printf ("wval->pid %d, wval->options %d", wval->pid, wval->options);
 | 
						|
 | 
						|
      /* If the first time for this thread, create a new event, otherwise
 | 
						|
       * reset the event.
 | 
						|
       */
 | 
						|
      if ((wval->ev = wval->thread_ev) == NULL)
 | 
						|
	{
 | 
						|
	  wval->ev = wval->thread_ev = CreateEvent (&sec_none_nih, TRUE,
 | 
						|
						    FALSE, NULL);
 | 
						|
	  ProtectHandle (wval->ev);
 | 
						|
	}
 | 
						|
      ResetEvent (wval->ev);
 | 
						|
 | 
						|
      /* Scan list of children to see if any have died.
 | 
						|
       * If so, the event flag is set so that the wait* ()
 | 
						|
       * process will return immediately.
 | 
						|
       *
 | 
						|
       * If no children were found and the wait option was WNOHANG,
 | 
						|
       * then set the pid to 0 and remove the waitq value from
 | 
						|
       * consideration.
 | 
						|
       */
 | 
						|
      w->next = wval;		/* set at end of wait queue */
 | 
						|
      if ((potential_match = checkstate (w)) <= 0)
 | 
						|
	{
 | 
						|
	  if (!potential_match)
 | 
						|
	    {
 | 
						|
	      w->next = NULL;		// don't want to keep looking
 | 
						|
	      wval->ev = NULL;		// flag that there are no children
 | 
						|
	      sip_printf ("no appropriate children, %p, %p",
 | 
						|
			  wval->thread_ev, wval->ev);
 | 
						|
	    }
 | 
						|
	  else if (wval->options & WNOHANG)
 | 
						|
	    {
 | 
						|
	      w->next = NULL;		// don't want to keep looking
 | 
						|
	      wval->pid = 0;		// didn't find a pid
 | 
						|
	      if (!SetEvent (wval->ev))	// wake up wait4 () immediately
 | 
						|
		system_printf ("Couldn't wake up wait event, %E");
 | 
						|
	      sip_printf ("WNOHANG and no terminated children, %p, %p",
 | 
						|
			  wval->thread_ev, wval->ev);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      if (w->next != NULL)
 | 
						|
	sip_printf ("wait activated %p, %p", wval->thread_ev, wval->ev);
 | 
						|
      else if (wval->ev != NULL)
 | 
						|
	sip_printf ("wait activated %p.  Reaped zombie.", wval->ev);
 | 
						|
      else
 | 
						|
	sip_printf ("wait not activated %p, %p", wval->thread_ev, wval->ev);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
out:
 | 
						|
  sync_proc_subproc->release ();	// Release the lock
 | 
						|
out1:
 | 
						|
  sip_printf ("returning %d", rc);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
/* Terminate the wait_subproc thread.
 | 
						|
 * 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.
 | 
						|
 */
 | 
						|
void __stdcall
 | 
						|
proc_terminate (void)
 | 
						|
{
 | 
						|
  sip_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
 | 
						|
  /* Signal processing is assumed to be blocked in this routine. */
 | 
						|
  if (hwait_subproc)
 | 
						|
    {
 | 
						|
      int rc;
 | 
						|
      proc_loop_wait = 0;	// Tell wait_subproc thread to exit
 | 
						|
      wake_wait_subproc ();	// Wake wait_subproc loop
 | 
						|
 | 
						|
      /* Wait for wait_subproc thread to exit (but not *too* long) */
 | 
						|
      if ((rc = WaitForSingleObject (hwait_subproc, WWSP)) != WAIT_OBJECT_0)
 | 
						|
	if (rc == WAIT_TIMEOUT)
 | 
						|
	  system_printf ("WFSO(hwait_subproc) timed out");
 | 
						|
	else
 | 
						|
	  system_printf ("WFSO(hwait_subproc), rc %d, %E", rc);
 | 
						|
 | 
						|
      HANDLE h = hwait_subproc;
 | 
						|
      hwait_subproc = NULL;
 | 
						|
      ForceCloseHandle1 (h, hwait_subproc);
 | 
						|
 | 
						|
      sync_proc_subproc->acquire(WPSP);
 | 
						|
      (void) proc_subproc (PROC_CLEARWAIT, 1);
 | 
						|
 | 
						|
      lock_pinfo_for_update (INFINITE);
 | 
						|
      /* Clean out zombie processes from the pid list. */
 | 
						|
      int i;
 | 
						|
      for (i = 0; i < nzombies; i++)
 | 
						|
	{
 | 
						|
	  pinfo *child;
 | 
						|
	  if ((child = zombies[i])->hProcess)
 | 
						|
	    {
 | 
						|
	      ForceCloseHandle1 (child->hProcess, childhProc);
 | 
						|
	      child->hProcess = NULL;
 | 
						|
	    }
 | 
						|
	  child->process_state = PID_NOT_IN_USE;
 | 
						|
	}
 | 
						|
 | 
						|
      /* Disassociate my subprocesses */
 | 
						|
      for (i = 0; i < nchildren; i++)
 | 
						|
	{
 | 
						|
	  pinfo *child;
 | 
						|
	  if ((child = pchildren[i])->process_state == PID_NOT_IN_USE)
 | 
						|
	    continue;		// Should never happen
 | 
						|
	  if (!child->hProcess)
 | 
						|
	    sip_printf ("%d(%d) hProcess cleared already?", child->pid,
 | 
						|
			child->dwProcessId);
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      ForceCloseHandle1 (child->hProcess, childhProc);
 | 
						|
	      child->hProcess = NULL;
 | 
						|
	      if (!proc_exists (child))
 | 
						|
		{
 | 
						|
		  sip_printf ("%d(%d) doesn't exist", child->pid,
 | 
						|
			      child->dwProcessId);
 | 
						|
		  child->process_state = PID_NOT_IN_USE;	/* a reaped child */
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  sip_printf ("%d(%d) closing active child handle", child->pid,
 | 
						|
			      child->dwProcessId);
 | 
						|
		  child->ppid = 1;
 | 
						|
		  if (child->pgid == myself->pid)
 | 
						|
		    child->process_state |= PID_ORPHANED;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      unlock_pinfo ();
 | 
						|
      nchildren = nzombies = 0;
 | 
						|
 | 
						|
      /* Attempt to close and release sync_proc_subproc in a
 | 
						|
       * non-raceable manner.
 | 
						|
       */
 | 
						|
      muto *m = sync_proc_subproc;
 | 
						|
      sync_proc_subproc = NULL;
 | 
						|
      delete m;
 | 
						|
    }
 | 
						|
  sip_printf ("leaving");
 | 
						|
}
 | 
						|
 | 
						|
/* Clear pending signal from the sigtodo array
 | 
						|
 */
 | 
						|
void __stdcall
 | 
						|
sig_clear (int sig)
 | 
						|
{
 | 
						|
  (void) InterlockedExchange (myself->getsigtodo(sig), 0L);
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* Force the wait_sig thread to wake up and scan the sigtodo array.
 | 
						|
 */
 | 
						|
extern "C" int __stdcall
 | 
						|
sig_dispatch_pending (int justwake)
 | 
						|
{
 | 
						|
  if (!hwait_sig)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  int was_pending = pending_signals;
 | 
						|
#ifdef DEBUGGING
 | 
						|
  sip_printf ("pending_signals %d", was_pending);
 | 
						|
#endif
 | 
						|
  if (!was_pending && !justwake)
 | 
						|
#ifdef DEBUGGING
 | 
						|
    sip_printf ("no need to wake anything up");
 | 
						|
#else
 | 
						|
    ;
 | 
						|
#endif
 | 
						|
  else
 | 
						|
    {
 | 
						|
      wait_for_me ();
 | 
						|
      if (!justwake)
 | 
						|
	(void) sig_send (myself, __SIGFLUSH);
 | 
						|
      else if (ReleaseSemaphore (sigcatch_nosync, 1, NULL))
 | 
						|
#ifdef DEBUGGING
 | 
						|
	sip_printf ("woke up wait_sig");
 | 
						|
#else
 | 
						|
	;
 | 
						|
#endif
 | 
						|
      else if (no_signals_available ())
 | 
						|
	/*sip_printf ("I'm going away now")*/;
 | 
						|
      else
 | 
						|
	system_printf ("%E releasing sigcatch_nosync(%p)", sigcatch_nosync);
 | 
						|
 
 | 
						|
    }
 | 
						|
  return was_pending;
 | 
						|
}
 | 
						|
 | 
						|
/* Message initialization.  Called from dll_crt0_1
 | 
						|
 *
 | 
						|
 * This routine starts the signal handling thread.  The wait_sig_inited
 | 
						|
 * event is used to signal that the thread is ready to handle signals.
 | 
						|
 * We don't wait for this during initialization but instead detect it
 | 
						|
 * in sig_send to gain a little concurrency.
 | 
						|
 */
 | 
						|
void __stdcall
 | 
						|
sigproc_init ()
 | 
						|
{
 | 
						|
  wait_sig_inited = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
 | 
						|
  ProtectHandle (wait_sig_inited);
 | 
						|
 | 
						|
  /* local event signaled when main thread has been dispatched
 | 
						|
     to a signal handler function. */
 | 
						|
  signal_arrived = CreateEvent(&sec_none_nih, TRUE, FALSE, NULL);
 | 
						|
 | 
						|
  maintid = GetCurrentThreadId ();// For use in determining if signals
 | 
						|
				  //  should be blocked.
 | 
						|
 | 
						|
  if (!(hwait_sig = makethread (wait_sig, NULL, 0, "sig")))
 | 
						|
    {
 | 
						|
      system_printf ("cannot create wait_sig thread, %E");
 | 
						|
      api_fatal ("terminating");
 | 
						|
    }
 | 
						|
 | 
						|
  ProtectHandle (hwait_sig);
 | 
						|
 | 
						|
  /* sync_proc_subproc is used by proc_subproc.  It serialises
 | 
						|
   * access to the children and zombie arrays.
 | 
						|
   */
 | 
						|
  sync_proc_subproc = new_muto (FALSE, "sync_proc_subproc");
 | 
						|
 | 
						|
  /* Initialize waitq structure for main thread.  A waitq structure is
 | 
						|
   * allocated for each thread that executes a wait to allow multiple threads
 | 
						|
   * to perform waits.  Pre-allocate a waitq structure for the main thread.
 | 
						|
   */
 | 
						|
  waitq *w;
 | 
						|
  if ((w = (waitq *)waitq_storage.get ()) == NULL)
 | 
						|
    {
 | 
						|
      w = &waitq_main;
 | 
						|
      waitq_storage.set (w);
 | 
						|
    }
 | 
						|
  memset (w, 0, sizeof *w);	// Just to be safe
 | 
						|
 | 
						|
  sip_printf ("process/signal handling enabled(%x)", myself->process_state);
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* Called on process termination to terminate signal and process threads.
 | 
						|
 */
 | 
						|
void __stdcall
 | 
						|
sigproc_terminate (void)
 | 
						|
{
 | 
						|
  HANDLE h = hwait_sig;
 | 
						|
  hwait_sig = NULL;
 | 
						|
 | 
						|
  if (GetCurrentThreadId () == sigtid)
 | 
						|
    {
 | 
						|
      ForceCloseHandle (sigcomplete_main);
 | 
						|
      for (int i = 0; i < 20; i++)
 | 
						|
	(void) ReleaseSemaphore (sigcomplete_nonmain, 1, NULL);
 | 
						|
      ForceCloseHandle (sigcomplete_nonmain);
 | 
						|
      ForceCloseHandle (sigcatch_main);
 | 
						|
      ForceCloseHandle (sigcatch_nonmain);
 | 
						|
      ForceCloseHandle (sigcatch_nosync);
 | 
						|
    }
 | 
						|
  proc_terminate ();		// Terminate process handling thread
 | 
						|
 | 
						|
  if (!sig_loop_wait)
 | 
						|
    sip_printf ("sigproc_terminate: sigproc handling not active");
 | 
						|
  else
 | 
						|
    {
 | 
						|
      sigproc_printf ("entering");
 | 
						|
      sig_loop_wait = 0;	// Tell wait_sig to exit when it is
 | 
						|
				//  finished with anything it is doing
 | 
						|
      sig_dispatch_pending (TRUE);	// wake up and die
 | 
						|
 | 
						|
      /* If !hwait_sig, then the process probably hasn't even finished
 | 
						|
       * its initialization phase.
 | 
						|
       */
 | 
						|
      if (hwait_sig)
 | 
						|
	{
 | 
						|
	  if (GetCurrentThreadId () != sigtid)
 | 
						|
	    WaitForSingleObject (h, 10000);
 | 
						|
	  ForceCloseHandle1 (h, hwait_sig);
 | 
						|
 | 
						|
	  /* Exiting thread.  Cleanup.  Don't set to inactive if a child has been
 | 
						|
	     execed with the same pid. */
 | 
						|
	  if (!myself->dwProcessId || myself->dwProcessId == GetCurrentProcessId ())
 | 
						|
	    myself->process_state &= ~PID_ACTIVE;
 | 
						|
	  else
 | 
						|
	    sip_printf ("Did not clear PID_ACTIVE since %d != %d",
 | 
						|
			myself->dwProcessId, GetCurrentProcessId ());
 | 
						|
 | 
						|
	  /* In case of a sigsuspend */
 | 
						|
	  SetEvent (signal_arrived);
 | 
						|
 | 
						|
	  if (GetCurrentThreadId () != sigtid)
 | 
						|
	    {
 | 
						|
	      ForceCloseHandle (sigcomplete_main);
 | 
						|
	      ForceCloseHandle (sigcomplete_nonmain);
 | 
						|
	      ForceCloseHandle (sigcatch_main);
 | 
						|
	      ForceCloseHandle (sigcatch_nonmain);
 | 
						|
	      ForceCloseHandle (sigcatch_nosync);
 | 
						|
	    }
 | 
						|
	}
 | 
						|
      sip_printf ("done");
 | 
						|
    }
 | 
						|
 | 
						|
  /* Set this so that subsequent tests will succeed. */
 | 
						|
  if (!myself->dwProcessId)
 | 
						|
    myself->dwProcessId = GetCurrentProcessId ();
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* Send a signal to another process by raising its signal semaphore.
 | 
						|
 * If pinfo *p == NULL, send to the current process.
 | 
						|
 * If sending to this process, wait for notification that a signal has
 | 
						|
 * completed before returning.
 | 
						|
 */
 | 
						|
int __stdcall
 | 
						|
sig_send (pinfo *p, int sig, DWORD ebp)
 | 
						|
{
 | 
						|
  int rc = 1;
 | 
						|
  DWORD tid = GetCurrentThreadId ();
 | 
						|
  BOOL its_me;
 | 
						|
  HANDLE thiscatch = NULL;
 | 
						|
  HANDLE thiscomplete = NULL;
 | 
						|
  BOOL wait_for_completion;
 | 
						|
  extern signal_dispatch sigsave;
 | 
						|
 | 
						|
  if (p == myself_nowait_nonmain)
 | 
						|
    p = (tid == maintid) ? myself : myself_nowait;
 | 
						|
  if (!(its_me = (p == NULL || p == myself || p == myself_nowait)))
 | 
						|
    wait_for_completion = FALSE;
 | 
						|
  else
 | 
						|
    {
 | 
						|
      if (no_signals_available ())
 | 
						|
	goto out;		// Either exiting or not yet initializing
 | 
						|
      wait_for_me ();
 | 
						|
      wait_for_completion = p != myself_nowait;
 | 
						|
      p = myself;
 | 
						|
    }
 | 
						|
 | 
						|
  /* It is possible that the process is not yet ready to receive messages
 | 
						|
   * or that it has exited.  Detect this.
 | 
						|
   */
 | 
						|
  if (!proc_can_be_signalled (p))	/* Is the process accepting messages? */
 | 
						|
    {
 | 
						|
      sip_printf ("invalid pid %d(%x), signal %d",
 | 
						|
		  p->pid, p->process_state, sig);
 | 
						|
      set_errno (ESRCH);
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
 | 
						|
  sip_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me);
 | 
						|
 | 
						|
  if (its_me)
 | 
						|
    {
 | 
						|
      if (!wait_for_completion)
 | 
						|
	thiscatch = sigcatch_nosync;
 | 
						|
      else if (tid != maintid)
 | 
						|
	{
 | 
						|
	  thiscatch = sigcatch_nonmain;
 | 
						|
	  thiscomplete = sigcomplete_nonmain;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  thiscatch = sigcatch_main;
 | 
						|
	  thiscomplete = sigcomplete_main;
 | 
						|
	  sigsave.ebp = ebp ?: (DWORD) __builtin_frame_address (1);
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else if (!(thiscatch = getsem (p, "sigcatch", 0, 0)))
 | 
						|
    goto out;		  // Couldn't get the semaphore.  getsem issued
 | 
						|
			  //  an error, if appropriate.
 | 
						|
 | 
						|
#if WHEN_MULTI_THREAD_SIGNALS_WORK
 | 
						|
  signal_dispatch *sd;
 | 
						|
  sd = signal_dispatch_storage.get ();
 | 
						|
  if (sd == NULL)
 | 
						|
    sd = signal_dispatch_storage.create ();
 | 
						|
#endif
 | 
						|
 | 
						|
  /* Increment the sigtodo array to signify which signal to assert.
 | 
						|
   */
 | 
						|
  (void) InterlockedIncrement (p->getsigtodo(sig));
 | 
						|
 | 
						|
  /* Notify the process that a signal has arrived.
 | 
						|
   */
 | 
						|
  SetLastError (0);
 | 
						|
 | 
						|
#if 0
 | 
						|
  int prio;
 | 
						|
  prio = GetThreadPriority (GetCurrentThread ());
 | 
						|
  (void) SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (!ReleaseSemaphore (thiscatch, 1, NULL) && (int) GetLastError () > 0)
 | 
						|
    {
 | 
						|
sigproc_printf ("ReleaseSemaphore failed, %E");
 | 
						|
      /* Couldn't signal the semaphore.  This probably means that the
 | 
						|
       * process is exiting.
 | 
						|
       */
 | 
						|
      if (!its_me)
 | 
						|
	ForceCloseHandle (thiscatch);
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  if (no_signals_available ())
 | 
						|
	    sip_printf ("I'm going away now");
 | 
						|
	  else if ((int) GetLastError () == -1)
 | 
						|
	    rc = WaitForSingleObject (thiscomplete, 500);
 | 
						|
	  else
 | 
						|
	    system_printf ("error sending signal %d to pid %d, semaphore %p, %E",
 | 
						|
			  sig, p->pid, thiscatch);
 | 
						|
	}
 | 
						|
      goto out;
 | 
						|
    }
 | 
						|
sigproc_printf ("ReleaseSemaphore succeeded");
 | 
						|
 | 
						|
  /* No need to wait for signal completion unless this was a signal to
 | 
						|
   * this process.
 | 
						|
   *
 | 
						|
   * If it was a signal to this process, wait for a dispatched signal.
 | 
						|
   * Otherwise just wait for the wait_sig to signal that it has finished
 | 
						|
   * processing the signal.
 | 
						|
   */
 | 
						|
  if (!wait_for_completion)
 | 
						|
    {
 | 
						|
      rc = WAIT_OBJECT_0;
 | 
						|
      sip_printf ("Not waiting for sigcomplete.  its_me %d sig %d", its_me, sig);
 | 
						|
      if (!its_me)
 | 
						|
	ForceCloseHandle (thiscatch);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      sip_printf ("Waiting for thiscomplete %p", thiscomplete);
 | 
						|
 | 
						|
      SetLastError (0);
 | 
						|
      rc = WaitForSingleObject (thiscomplete, WSSC);
 | 
						|
      /* Check for strangeness due to this thread being redirected by the
 | 
						|
	 signal handler.  Sometimes a WAIT_TIMEOUT will occur when the
 | 
						|
	 thread hasn't really timed out.  So, check again.
 | 
						|
	 FIXME: This isn't foolproof. */
 | 
						|
      if (rc != WAIT_OBJECT_0 &&
 | 
						|
	  WaitForSingleObject (thiscomplete, 0) == WAIT_OBJECT_0)
 | 
						|
	rc = WAIT_OBJECT_0;
 | 
						|
    }
 | 
						|
 | 
						|
#if 0
 | 
						|
  SetThreadPriority (GetCurrentThread (), prio);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (rc == WAIT_OBJECT_0)
 | 
						|
    rc = 0;		// Successful exit
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* It's an error unless sig_loop_wait == 0 (the process is exiting). */
 | 
						|
      if (!no_signals_available ())
 | 
						|
	system_printf ("wait for sig_complete event failed, sig %d, rc %d, %E",
 | 
						|
		      sig, rc);
 | 
						|
      set_errno (ENOSYS);
 | 
						|
      rc = -1;
 | 
						|
    }
 | 
						|
 | 
						|
out:
 | 
						|
  sip_printf ("returning %d from sending signal %d", rc, sig);
 | 
						|
  return rc;
 | 
						|
}
 | 
						|
 | 
						|
/* Set pending signal from the sigtodo array
 | 
						|
 */
 | 
						|
void __stdcall
 | 
						|
sig_set_pending (int sig)
 | 
						|
{
 | 
						|
  (void) InterlockedIncrement (myself->getsigtodo(sig));
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* 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);
 | 
						|
  if (!(hwait_subproc = makethread (wait_subproc, NULL, 0, "+proc")))
 | 
						|
    system_printf ("cannot create wait_subproc thread, %E");
 | 
						|
  ProtectHandle (events[0]);
 | 
						|
  ProtectHandle (hwait_subproc);
 | 
						|
  sip_printf ("started wait_subproc thread %p", hwait_subproc);
 | 
						|
}
 | 
						|
 | 
						|
/* Initialize some of the memory block passed to child processes
 | 
						|
   by fork/spawn/exec. */
 | 
						|
 | 
						|
void __stdcall
 | 
						|
init_child_info (DWORD chtype, child_info *ch, int pid, HANDLE subproc_ready)
 | 
						|
{
 | 
						|
  subproc_init ();
 | 
						|
  memset (ch, 0, sizeof *ch);
 | 
						|
  ch->cb = sizeof *ch;
 | 
						|
  ch->type = chtype;
 | 
						|
  ch->cygpid = pid;
 | 
						|
  ch->shared_h = cygwin_shared_h;
 | 
						|
  ch->console_h = console_shared_h;
 | 
						|
  ch->subproc_ready = subproc_ready;
 | 
						|
  if (chtype != PROC_EXEC || !parent_alive)
 | 
						|
    ch->parent_alive = hwait_subproc;
 | 
						|
  else if (parent_alive)
 | 
						|
    DuplicateHandle (hMainProc, parent_alive, hMainProc, &ch->parent_alive,
 | 
						|
		     0, 1, DUPLICATE_SAME_ACCESS);
 | 
						|
}
 | 
						|
 | 
						|
/* Check the state of all of our children to see if any are stopped or
 | 
						|
 * terminated.
 | 
						|
 */
 | 
						|
static int __stdcall
 | 
						|
checkstate (waitq *w)
 | 
						|
{
 | 
						|
  int i, x, potential_match = 0;
 | 
						|
  pinfo *child;
 | 
						|
 | 
						|
  sip_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
 | 
						|
 | 
						|
  /* Check already dead processes first to see if they match the criteria
 | 
						|
   * given in w->next.
 | 
						|
   */
 | 
						|
  for (i = 0; i < nzombies; i++)
 | 
						|
    if ((x = stopped_or_terminated (w, child = zombies[i])) < 0)
 | 
						|
      potential_match = -1;
 | 
						|
    else if (x > 0)
 | 
						|
      {
 | 
						|
	remove_zombie (i);
 | 
						|
	potential_match = 1;
 | 
						|
	goto out;
 | 
						|
      }
 | 
						|
 | 
						|
  sip_printf ("checking alive children");
 | 
						|
 | 
						|
  /* No dead terminated children matched.  Check for stopped children. */
 | 
						|
  for (i = 0; i < nchildren; i++)
 | 
						|
    if ((x = stopped_or_terminated (w, pchildren[i])) < 0)
 | 
						|
      potential_match = -1;
 | 
						|
    else if (x > 0)
 | 
						|
      {
 | 
						|
	potential_match = 1;
 | 
						|
	break;
 | 
						|
      }
 | 
						|
 | 
						|
out:
 | 
						|
  sip_printf ("returning %d", potential_match);
 | 
						|
  return potential_match;
 | 
						|
}
 | 
						|
 | 
						|
/* Get or create a process specific semaphore used in message passing.
 | 
						|
 */
 | 
						|
static HANDLE __stdcall
 | 
						|
getsem (pinfo *p, const char *str, int init, int max)
 | 
						|
{
 | 
						|
  HANDLE h;
 | 
						|
 | 
						|
  if (p != NULL)
 | 
						|
    {
 | 
						|
      if (!proc_can_be_signalled (p))
 | 
						|
	{
 | 
						|
	  set_errno (ESRCH);
 | 
						|
	  return NULL;
 | 
						|
	}
 | 
						|
      int wait = 10000;
 | 
						|
      sip_printf ("pid %d, ppid %d, wait %d, initializing %x", p->pid, p->ppid, wait,
 | 
						|
		  ISSTATE (p, PID_INITIALIZING));
 | 
						|
      for (int i = 0; ISSTATE (p, PID_INITIALIZING) && i < wait; i++)
 | 
						|
	Sleep (1);
 | 
						|
    }
 | 
						|
 | 
						|
  SetLastError (0);
 | 
						|
  if (p == NULL)
 | 
						|
    {
 | 
						|
      char sa_buf[1024];
 | 
						|
 | 
						|
      DWORD winpid = GetCurrentProcessId ();
 | 
						|
      h = CreateSemaphore (allow_ntsec ? sec_user (sa_buf) : &sec_none_nih,
 | 
						|
			   init, max, str = shared_name (str, winpid));
 | 
						|
      p = myself;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
 | 
						|
			 str = shared_name (str, p->dwProcessId));
 | 
						|
 | 
						|
      if (h == NULL)
 | 
						|
	{
 | 
						|
	  if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p))
 | 
						|
	    set_errno (ESRCH);
 | 
						|
	  else
 | 
						|
	    set_errno (EPERM);
 | 
						|
	  return NULL;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  if (!h)
 | 
						|
    {
 | 
						|
      system_printf ("can't %s %s, %E", p ? "open" : "create", str);
 | 
						|
      set_errno (ESRCH);
 | 
						|
    }
 | 
						|
  return h;
 | 
						|
}
 | 
						|
 | 
						|
/* Get the sync_proc_subproc muto to control access to
 | 
						|
 * children, zombie arrays.
 | 
						|
 * Attempt to handle case where process is exiting as we try to grab
 | 
						|
 * the mutex.
 | 
						|
 */
 | 
						|
static __inline__ BOOL
 | 
						|
get_proc_lock (DWORD what, DWORD val)
 | 
						|
{
 | 
						|
  Static int lastwhat = -1;
 | 
						|
  if (!sync_proc_subproc)
 | 
						|
    return FALSE;
 | 
						|
  if (sync_proc_subproc->acquire (WPSP))
 | 
						|
    {
 | 
						|
      lastwhat = what;
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  if (!sync_proc_subproc)
 | 
						|
    return FALSE;
 | 
						|
  system_printf ("Couldn't aquire sync_proc_subproc for(%d,%d), %E, last %d",
 | 
						|
		  what, val, lastwhat);
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* Remove a child from pchildren/hchildren by swapping it with the
 | 
						|
 * last child in the list.
 | 
						|
 */
 | 
						|
static void __stdcall
 | 
						|
remove_child (int ci)
 | 
						|
{
 | 
						|
  sip_printf ("removing [%d], pid %d, handle %p, nchildren %d",
 | 
						|
	      ci, pchildren[ci]->pid, hchildren[ci], nchildren);
 | 
						|
  if (ci < --nchildren)
 | 
						|
    {
 | 
						|
      pchildren[ci] = pchildren[nchildren];
 | 
						|
      hchildren[ci] = hchildren[nchildren];
 | 
						|
    }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* Remove a zombie from zombies by swapping it with the last child in the list.
 | 
						|
 */
 | 
						|
static void __stdcall
 | 
						|
remove_zombie (int ci)
 | 
						|
{
 | 
						|
  sip_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
 | 
						|
	      nzombies);
 | 
						|
  if (ci < --nzombies)
 | 
						|
    zombies[ci] = zombies[nzombies];
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
/* 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
 | 
						|
stopped_or_terminated (waitq *parent_w, pinfo *child)
 | 
						|
{
 | 
						|
  int potential_match;
 | 
						|
  waitq *w = parent_w->next;
 | 
						|
 | 
						|
  sip_printf ("considering pid %d", child->pid);
 | 
						|
  if (w->pid == -1)
 | 
						|
    potential_match = 1;
 | 
						|
  else if (w->pid == 0)
 | 
						|
    potential_match = child->pgid == myself->pgid;
 | 
						|
  else if (w->pid < 0)
 | 
						|
    potential_match = child->pgid == -w->pid;
 | 
						|
  else
 | 
						|
    potential_match = (w->pid == child->pid);
 | 
						|
 | 
						|
  if (!potential_match)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  BOOL terminated;
 | 
						|
 | 
						|
  if ((terminated = child->process_state == PID_ZOMBIE) ||
 | 
						|
      (w->options & WUNTRACED) && child->stopsig)
 | 
						|
    {
 | 
						|
      parent_w->next = w->next;	/* successful wait.  remove from wait queue */
 | 
						|
      w->pid = child->pid;
 | 
						|
 | 
						|
      if (!terminated)
 | 
						|
	{
 | 
						|
	  sip_printf ("stopped child");
 | 
						|
	  w->status = (child->stopsig << 8) | 0x7f;
 | 
						|
	  child->stopsig = 0;
 | 
						|
	}
 | 
						|
      else
 | 
						|
	{
 | 
						|
	  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);
 | 
						|
	    }
 | 
						|
	  ForceCloseHandle1 (child->hProcess, childhProc);
 | 
						|
	  child->hProcess = NULL;
 | 
						|
	  child->process_state = PID_NOT_IN_USE;	/* a reaped child */
 | 
						|
	}
 | 
						|
 | 
						|
      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;
 | 
						|
}
 | 
						|
 | 
						|
/* Process signals by waiting for a semaphore to become signaled.
 | 
						|
 * Then scan an in-memory array representing queued signals.
 | 
						|
 * Executes in a separate thread.
 | 
						|
 *
 | 
						|
 * Signals sent from this process are sent a completion signal so
 | 
						|
 * that returns from kill/raise do not occur until the signal has
 | 
						|
 * has been handled, as per POSIX.
 | 
						|
 */
 | 
						|
static DWORD WINAPI
 | 
						|
wait_sig (VOID *)
 | 
						|
{
 | 
						|
  /* Initialization */
 | 
						|
  (void) SetThreadPriority (hwait_sig, WAIT_SIG_PRIORITY);
 | 
						|
 | 
						|
  /* sigcatch_nosync       - semaphore incremented by sig_dispatch_pending and
 | 
						|
   *			     by foreign processes to force an examination of
 | 
						|
   *			     the sigtodo array.
 | 
						|
   * sigcatch_main	   - ditto for local main thread.
 | 
						|
   * sigcatch_nonmain      - ditto for local non-main threads.
 | 
						|
   *
 | 
						|
   * sigcomplete_main	   - event used to signal main thread on signal
 | 
						|
   *			     completion
 | 
						|
   * sigcomplete_nonmain   - semaphore signaled for non-main thread on signal
 | 
						|
   *			     completion
 | 
						|
   */
 | 
						|
  sigcatch_nosync = getsem (NULL, "sigcatch", 0, MAXLONG);
 | 
						|
  sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
 | 
						|
  sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
 | 
						|
  sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL);
 | 
						|
  sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
 | 
						|
  sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain);
 | 
						|
 | 
						|
  /* Setting dwProcessId flags that this process is now capable of receiving
 | 
						|
   * 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;
 | 
						|
 | 
						|
  ProtectHandle (sigcatch_nosync);
 | 
						|
  ProtectHandle (sigcatch_nonmain);
 | 
						|
  ProtectHandle (sigcatch_main);
 | 
						|
  ProtectHandle (sigcomplete_nonmain);
 | 
						|
  ProtectHandle (sigcomplete_main);
 | 
						|
 | 
						|
  /* 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");
 | 
						|
      ForceCloseHandle (child_proc_info->subproc_ready);
 | 
						|
    }
 | 
						|
 | 
						|
  SetEvent (wait_sig_inited);
 | 
						|
  sigtid = GetCurrentThreadId ();
 | 
						|
 | 
						|
  /* If we got something like a SIGINT while we were initializing, the
 | 
						|
     signal thread should be waiting for this event.  This signals the
 | 
						|
     thread that it's ok to send the signal since the wait_sig thread
 | 
						|
     is now active. */
 | 
						|
  extern HANDLE console_handler_thread_waiter;
 | 
						|
  SetEvent (console_handler_thread_waiter);
 | 
						|
 | 
						|
  HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync};
 | 
						|
  sigproc_printf ("Ready.  dwProcessid %d", myself->dwProcessId);
 | 
						|
  for (;;)
 | 
						|
    {
 | 
						|
      DWORD rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait);
 | 
						|
 | 
						|
      /* sigproc_terminate sets sig_loop_wait to zero to indicate that
 | 
						|
       * this thread should terminate.
 | 
						|
       */
 | 
						|
      if (rc == WAIT_TIMEOUT)
 | 
						|
	if (!sig_loop_wait)
 | 
						|
	  break;			// Exiting
 | 
						|
	else
 | 
						|
	  continue;
 | 
						|
 | 
						|
      if (rc == WAIT_FAILED)
 | 
						|
	{
 | 
						|
	  if (sig_loop_wait != 0)
 | 
						|
	    system_printf ("WFMO failed, %E");
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      rc -= WAIT_OBJECT_0;
 | 
						|
      int dispatched = FALSE;
 | 
						|
      sip_printf ("awake");
 | 
						|
      /* A sigcatch semaphore has been signaled.  Scan the sigtodo
 | 
						|
       * array looking for any unprocessed signals.
 | 
						|
       */
 | 
						|
      pending_signals = 0;
 | 
						|
      int saw_sigchld = 0;
 | 
						|
      int dispatched_sigchld = 0;
 | 
						|
      for (int sig = -__SIGOFFSET; sig < NSIG; sig++)
 | 
						|
	{
 | 
						|
	  while (InterlockedDecrement (myself->getsigtodo(sig)) >= 0)
 | 
						|
	    {
 | 
						|
	      if (sig == SIGCHLD)
 | 
						|
		saw_sigchld = 1;
 | 
						|
	      if (sig > 0 && sig != SIGCONT && sig != SIGKILL && sig != SIGSTOP &&
 | 
						|
		  (sigismember (& myself->getsigmask (), sig) ||
 | 
						|
		   myself->process_state & PID_STOPPED))
 | 
						|
		{
 | 
						|
		  sip_printf ("sig %d blocked", sig);
 | 
						|
		  break;
 | 
						|
		}
 | 
						|
 | 
						|
	      /* Found a signal to process */
 | 
						|
	      sip_printf ("processing signal %d", sig);
 | 
						|
	      switch (sig)
 | 
						|
		{
 | 
						|
		case __SIGFLUSH:
 | 
						|
		  /* just forcing the loop */
 | 
						|
		  break;
 | 
						|
 | 
						|
		/* Internal signal to force a flush of strace data to disk. */
 | 
						|
		case __SIGSTRACE:
 | 
						|
		  // proc_strace ();	// Dump cached strace.prntf stuff.
 | 
						|
		  break;
 | 
						|
 | 
						|
		/* Signalled from a child process that it has stopped */
 | 
						|
		case __SIGCHILDSTOPPED:
 | 
						|
		  sip_printf ("Received child stopped notification");
 | 
						|
		  dispatched |= sig_handle (SIGCHLD, rc);
 | 
						|
		  if (proc_subproc (PROC_CHILDSTOPPED, 0))
 | 
						|
		    dispatched |= 1;
 | 
						|
		  break;
 | 
						|
 | 
						|
		/* A normal UNIX signal */
 | 
						|
		default:
 | 
						|
		  sip_printf ("Got signal %d", sig);
 | 
						|
		  int wasdispatched = sig_handle (sig, rc);
 | 
						|
		  dispatched |= wasdispatched;
 | 
						|
		  if (sig == SIGCHLD && wasdispatched)
 | 
						|
		    dispatched_sigchld = 1;
 | 
						|
		  goto nextsig;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  /* Decremented too far. */
 | 
						|
	  if (InterlockedIncrement (myself->getsigtodo(sig)) > 0)
 | 
						|
	    pending_signals = 1;
 | 
						|
	nextsig:
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      if (saw_sigchld && !dispatched_sigchld)
 | 
						|
	proc_subproc (PROC_CLEARWAIT, 0);
 | 
						|
      /* Signal completion of signal handling depending on which semaphore
 | 
						|
       * woke up the WaitForMultipleObjects above.
 | 
						|
       */
 | 
						|
      switch (rc)
 | 
						|
	{
 | 
						|
	case 0:
 | 
						|
	  SetEvent (sigcomplete_main);
 | 
						|
sigproc_printf ("signalled sigcomplete_main %p", sigcomplete_main);
 | 
						|
	  break;
 | 
						|
	case 1:
 | 
						|
	  ReleaseSemaphore (sigcomplete_nonmain, 1, NULL);
 | 
						|
sigproc_printf ("signalled sigcomplete_nonmain %p", sigcomplete_nonmain);
 | 
						|
	  break;
 | 
						|
	default:
 | 
						|
sigproc_printf ("Did not signal anyone");
 | 
						|
	  /* Signal from another process.  No need to synchronize. */
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      if (dispatched < 0)
 | 
						|
	pending_signals = 1;
 | 
						|
      sip_printf ("looping");
 | 
						|
    }
 | 
						|
 | 
						|
  sip_printf ("done");
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Wait for subprocesses to terminate. Executes in a separate thread. */
 | 
						|
static DWORD WINAPI
 | 
						|
wait_subproc (VOID *)
 | 
						|
{
 | 
						|
  sip_printf ("starting");
 | 
						|
  int errloop = 0;
 | 
						|
 | 
						|
  for (;;)
 | 
						|
    {
 | 
						|
      DWORD rc = WaitForMultipleObjects (nchildren + 1, events, FALSE,
 | 
						|
					 proc_loop_wait);
 | 
						|
      if (rc == WAIT_TIMEOUT)
 | 
						|
	if (!proc_loop_wait)
 | 
						|
	  break;			// Exiting
 | 
						|
	else
 | 
						|
	  continue;
 | 
						|
 | 
						|
      if (rc == WAIT_FAILED)
 | 
						|
	{
 | 
						|
	  if (!proc_loop_wait)
 | 
						|
	    break;
 | 
						|
 | 
						|
	  /* 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 < 10 && GetLastError () == ERROR_INVALID_HANDLE)
 | 
						|
	    continue;
 | 
						|
 | 
						|
	  system_printf ("wait failed. nchildren %d, wait %d, %E",
 | 
						|
			nchildren, proc_loop_wait);
 | 
						|
 | 
						|
	  for (int i = 0; i < nchildren + 1; i++)
 | 
						|
	    if ((rc = WaitForSingleObject (events[i], 0)) == WAIT_OBJECT_0 ||
 | 
						|
		rc == WAIT_TIMEOUT)
 | 
						|
	      continue;
 | 
						|
	    else
 | 
						|
	      system_printf ("event[%d] %p, %E", i, events[0]);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      errloop = 0;
 | 
						|
      rc -= WAIT_OBJECT_0;
 | 
						|
      if (rc-- != 0)
 | 
						|
	(void)proc_subproc (PROC_CHILDTERMINATED, rc);
 | 
						|
      sip_printf ("looping");
 | 
						|
    }
 | 
						|
 | 
						|
  ForceCloseHandle (events[0]);
 | 
						|
  events[0] = NULL;
 | 
						|
  sip_printf ("done");
 | 
						|
  return 0;
 | 
						|
}
 |