summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2003-09-24 17:10:21 +0000
committerChristopher Faylor <cgf@redhat.com>2003-09-24 17:10:21 +0000
commita57b4c333e3c45f445b17ab3ab06c9c579da5f84 (patch)
treefc333a070377fdb7e48e70321674638061049ba9
parent56fc2de784ceb281868e0b8e6b65fe6d02041261 (diff)
downloadgdb-cvs/cr-0x9c.tar.gz
* dcrt0.cc (do_exit): Eliminate "C" linkage. Call events_terminate early.cvs/cr-0x9ccr-0x9c
(exit_states): Move out of source file into header file. * winsup.h: Move exit_states here. Remove "C" linkage from do_exit declaration. * debug.cc (lock_debug): Remove explicit (and incorrect) external for exit_state. * sigproc.cc (sig_dispatch_pending): Don't flush signals if exiting.
-rw-r--r--winsup/cygwin/ChangeLog11
-rw-r--r--winsup/cygwin/dcrt0.cc28
-rw-r--r--winsup/cygwin/debug.cc225
-rw-r--r--winsup/cygwin/sigproc.cc1379
-rw-r--r--winsup/cygwin/winsup.h334
5 files changed, 1956 insertions, 21 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index f992778ccdd..dc103744e21 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,14 @@
+2003-09-22 Christopher Faylor <cgf@redhat.com>
+
+ * dcrt0.cc (do_exit): Eliminate "C" linkage. Call events_terminate
+ early.
+ (exit_states): Move out of source file into header file.
+ * winsup.h: Move exit_states here. Remove "C" linkage from do_exit
+ declaration.
+ * debug.cc (lock_debug): Remove explicit (and incorrect) external for
+ exit_state.
+ * sigproc.cc (sig_dispatch_pending): Don't flush signals if exiting.
+
2003-09-20 Christopher Faylor <cgf@redhat.com>
* spawn.cc (pthread_cleanup): New struct.
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 51cc55f2529..1933f8cfe53 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -956,26 +956,18 @@ __main (void)
do_global_ctors (user_data->ctors, FALSE);
}
-enum exit_states
- {
- ES_NOT_EXITING = 0,
- ES_THREADTERM,
- ES_SIGNAL,
- ES_CLOSEALL,
- ES_SIGPROCTERMINATE,
- ES_TITLE,
- ES_HUP_PGRP,
- ES_HUP_SID,
- ES_TTY_TERMINATE,
- ES_EVENTS_TERMINATE
- };
-
exit_states NO_COPY exit_state;
extern CRITICAL_SECTION exit_lock;
-extern "C" void __stdcall
+void __stdcall
do_exit (int status)
{
+ if (exit_state < ES_EVENTS_TERMINATE)
+ {
+ exit_state = ES_EVENTS_TERMINATE;
+ events_terminate ();
+ }
+
EnterCriticalSection (&exit_lock);
UINT n = (UINT) status;
@@ -1059,12 +1051,6 @@ do_exit (int status)
tty_terminate ();
}
- if (exit_state < ES_EVENTS_TERMINATE)
- {
- exit_state = ES_EVENTS_TERMINATE;
- events_terminate ();
- }
-
minimal_printf ("winpid %d, exit %d", GetCurrentProcessId (), n);
myself->exit (n);
}
diff --git a/winsup/cygwin/debug.cc b/winsup/cygwin/debug.cc
new file mode 100644
index 00000000000..1b4084febef
--- /dev/null
+++ b/winsup/cygwin/debug.cc
@@ -0,0 +1,225 @@
+/* debug.cc
+
+ Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "perthread.h"
+#include "perprocess.h"
+#include "security.h"
+#include "cygerrno.h"
+#ifdef DEBUGGING
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#endif
+
+#undef CloseHandle
+
+#ifdef DEBUGGING
+/* Here lies extra debugging routines which help track down internal
+ Cygwin problems when compiled with -DDEBUGGING . */
+#include <stdlib.h>
+#define NFREEH (sizeof (cygheap->debug.freeh) / sizeof (cygheap->debug.freeh[0]))
+
+class lock_debug
+{
+ static muto *locker;
+ bool acquired;
+ public:
+ lock_debug () : acquired (0)
+ {
+ if (locker && !exit_state)
+ acquired = !!locker->acquire (INFINITE);
+ }
+ void unlock ()
+ {
+ if (locker && acquired)
+ {
+ locker->release ();
+ acquired = false;
+ }
+ }
+ ~lock_debug () {unlock ();}
+ friend void debug_init ();
+};
+
+muto NO_COPY *lock_debug::locker = NULL;
+
+static bool __stdcall mark_closed (const char *, int, HANDLE, const char *, BOOL);
+
+void
+debug_init ()
+{
+ muto *debug_lock_muto;
+ lock_debug::locker = new_muto (debug_lock_muto);
+}
+
+/* Find a registered handle in the linked list of handles. */
+static handle_list * __stdcall
+find_handle (HANDLE h)
+{
+ handle_list *hl;
+ for (hl = &cygheap->debug.starth; hl->next != NULL; hl = hl->next)
+ if (hl->next->h == h)
+ goto out;
+ cygheap->debug.endh = hl;
+ hl = NULL;
+
+out:
+ return hl;
+}
+
+#ifdef DEBUGGING_AND_FDS_PROTECTED
+void
+setclexec (HANDLE oh, HANDLE nh, bool not_inheriting)
+{
+ handle_list *hl = find_handle (oh);
+ if (hl)
+ {
+ hl = hl->next;
+ hl->inherited = !not_inheriting;
+ hl->h = nh;
+ }
+}
+#endif
+
+/* Create a new handle record */
+static handle_list * __stdcall
+newh ()
+{
+ handle_list *hl;
+ lock_debug here;
+
+ for (hl = cygheap->debug.freeh; hl < cygheap->debug.freeh + NFREEH; hl++)
+ if (hl->name == NULL)
+ return hl;
+
+ return NULL;
+}
+
+/* Add a handle to the linked list of known handles. */
+void __stdcall
+add_handle (const char *func, int ln, HANDLE h, const char *name, bool inh)
+{
+ handle_list *hl;
+ lock_debug here;
+
+ if ((hl = find_handle (h)))
+ {
+ hl = hl->next;
+ if (hl->name == name && hl->func == func && hl->ln == ln)
+ return;
+ system_printf ("%s:%d - multiple attempts to add handle %s<%p>", func,
+ ln, name, h);
+ system_printf (" previously allocated by %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
+ return;
+ }
+
+ if ((hl = newh ()) == NULL)
+ {
+ here.unlock ();
+ debug_printf ("couldn't allocate memory for %s(%d): %s(%p)",
+ func, ln, name, h);
+ return;
+ }
+ hl->h = h;
+ hl->name = name;
+ hl->func = func;
+ hl->ln = ln;
+ hl->next = NULL;
+ hl->inherited = inh;
+ hl->pid = GetCurrentProcessId ();
+ cygheap->debug.endh->next = hl;
+ cygheap->debug.endh = hl;
+ debug_printf ("protecting handle '%s', inherited flag %d", hl->name, hl->inherited);
+
+ return;
+}
+
+static void __stdcall
+delete_handle (handle_list *hl)
+{
+ handle_list *hnuke = hl->next;
+ debug_printf ("nuking handle '%s'", hnuke->name);
+ hl->next = hl->next->next;
+ memset (hnuke, 0, sizeof (*hnuke));
+}
+
+void
+debug_fixup_after_fork_exec ()
+{
+ /* No lock needed at this point */
+ handle_list *hl;
+ for (hl = &cygheap->debug.starth; hl->next != NULL; /* nothing */)
+ if (hl->next->inherited)
+ hl = hl->next;
+ else
+ delete_handle (hl); // removes hl->next
+}
+
+static bool __stdcall
+mark_closed (const char *func, int ln, HANDLE h, const char *name, BOOL force)
+{
+ handle_list *hl;
+ lock_debug here;
+
+ if ((hl = find_handle (h)) && !force)
+ {
+ hl = hl->next;
+ here.unlock (); // race here
+ system_printf ("attempt to close protected handle %s:%d(%s<%p>) winpid %d",
+ hl->func, hl->ln, hl->name, hl->h, hl->pid);
+ system_printf (" by %s:%d(%s<%p>)", func, ln, name, h);
+ return FALSE;
+ }
+
+ handle_list *hln;
+ if (hl && (hln = hl->next) && strcmp (name, hln->name))
+ {
+ system_printf ("closing protected handle %s:%d(%s<%p>)",
+ hln->func, hln->ln, hln->name, hln->h);
+ system_printf (" by %s:%d(%s<%p>)", func, ln, name, h);
+ }
+
+ if (hl)
+ delete_handle (hl);
+
+ return TRUE;
+}
+
+/* Close a known handle. Complain if !force and closing a known handle or
+ if the name of the handle being closed does not match the registered name. */
+BOOL __stdcall
+close_handle (const char *func, int ln, HANDLE h, const char *name, BOOL force)
+{
+ BOOL ret;
+ lock_debug here;
+
+ if (!mark_closed (func, ln, h, name, force))
+ return FALSE;
+
+ ret = CloseHandle (h);
+
+#if 0 /* Uncomment to see CloseHandle failures */
+ if (!ret)
+ small_printf ("CloseHandle(%s) failed %s:%d\n", name, func, ln);
+#endif
+ return ret;
+}
+
+int __stdcall
+__set_errno (const char *func, int ln, int val)
+{
+ debug_printf ("%s:%d val %d", func, ln, val);
+ return errno = val;
+}
+#endif /*DEBUGGING*/
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
new file mode 100644
index 00000000000..ed927ed3663
--- /dev/null
+++ b/winsup/cygwin/sigproc.cc
@@ -0,0 +1,1379 @@
+/* sigproc.cc: inter/intra signal and sub process handler
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+ 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 "winsup.h"
+#include <stdlib.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <assert.h>
+#include <sys/signal.h>
+#include "cygerrno.h"
+#include "sync.h"
+#include "sigproc.h"
+#include "pinfo.h"
+#include "security.h"
+#include "fhandler.h"
+#include "path.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "child_info_magic.h"
+#define NEED_VFORK
+#include "perthread.h"
+#include "shared_info.h"
+#include "cygthread.h"
+
+/*
+ * 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 TOTSIGS (NSIG + __SIGOFFSET)
+
+#define wake_wait_subproc() SetEvent (events[0])
+
+#define no_signals_available() (!hwait_sig || !sig_loop_wait)
+
+#define NZOMBIES 256
+
+static LONG local_sigtodo[TOTSIGS];
+struct sigaction *global_sigs;
+
+inline LONG *
+getlocal_sigtodo (int sig)
+{
+ return local_sigtodo + __SIGOFFSET + sig;
+}
+
+void __stdcall
+sigalloc ()
+{
+ cygheap->sigs = global_sigs =
+ (struct sigaction *) ccalloc (HEAP_SIGS, NSIG, sizeof (struct sigaction));
+}
+
+void __stdcall
+signal_fixup_after_exec ()
+{
+ global_sigs = cygheap->sigs;
+ /* Set up child's signal handlers */
+ for (int i = 0; i < NSIG; i++)
+ {
+ myself->getsig (i).sa_mask = 0;
+ if (myself->getsig (i).sa_handler != SIG_IGN)
+ myself->getsig (i).sa_handler = SIG_DFL;
+ }
+}
+
+/*
+ * 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 = 1000; // Wait for subprocesses to exit
+Static DWORD sig_loop_wait = INFINITE; // Wait for signals to arrive
+
+Static HANDLE sigcatch_nonmain; // The semaphore signaled when
+ // signals are available for
+ // processing from non-main thread
+Static HANDLE sigcatch_main; // Signalled when main thread sends a
+ // signal
+Static HANDLE sigcatch_nosync; // Signal wait_sig to scan sigtodo
+ // but not to bother with any
+ // synchronization
+Static HANDLE sigcomplete_main; // Event signaled when a signal has
+ // finished processing for the main
+ // thread
+Static HANDLE sigcomplete_nonmain; // Semaphore raised for non-main
+ // threads when a signal has finished
+ // processing
+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 char cpchildren[PSIZE * sizeof (pinfo)]; // All my children info
+Static int nchildren; // Number of active children
+Static char czombies[(NZOMBIES + 1) * sizeof (pinfo)]; // All my deceased children info
+Static int nzombies; // Number of deceased children
+
+#define pchildren ((pinfo *) cpchildren)
+#define zombies ((pinfo *) czombies)
+
+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 sigtid = 0; // ID of the signal thread
+
+bool NO_COPY pending_signals = false; // true if signals pending
+
+/* Functions
+ */
+static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
+static __inline__ BOOL get_proc_lock (DWORD, DWORD);
+static HANDLE __stdcall getevent (_pinfo *, const char *) __attribute__ ((regparm (2)));
+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 (!myself->ppid_handle)
+ {
+ debug_printf ("No myself->ppid_handle");
+ 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;
+}
+
+void __stdcall
+wait_for_sigthread ()
+{
+ sigproc_printf ("wait_sig_inited %p", wait_sig_inited);
+ HANDLE hsig_inited = wait_sig_inited;
+ (void) WaitForSingleObject (hsig_inited, INFINITE);
+ wait_sig_inited = NULL;
+ (void) ForceCloseHandle1 (hsig_inited, wait_sig_inited);
+}
+
+/* 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 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;
+}
+
+static BOOL __stdcall
+proc_can_be_signalled (_pinfo *p)
+{
+ if (p == myself_nowait || p == myself_nowait_nonmain || p == myself)
+ {
+ assert (!wait_sig_inited);
+ return 1;
+ }
+
+ return ISSTATE (p, PID_INITIALIZING) ||
+ (((p)->process_state & (PID_ACTIVE | PID_IN_USE)) ==
+ (PID_ACTIVE | PID_IN_USE));
+}
+
+BOOL __stdcall
+pid_exists (pid_t pid)
+{
+ pinfo p (pid);
+ return proc_exists (p);
+}
+
+/* Test to determine if a process really exists and is processing signals.
+ */
+BOOL __stdcall
+proc_exists (_pinfo *p)
+{
+ return p && !(p->process_state & PID_EXITED);
+}
+
+/* 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
+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;
+}
+
+/* Handle all subprocess requests
+ */
+#define vchild (*((pinfo *) val))
+int __stdcall
+proc_subproc (DWORD what, DWORD val)
+{
+ int rc = 1;
+ int potential_match;
+ _pinfo *child;
+ int clearing;
+ waitq *w;
+
+#define wval ((waitq *) val)
+
+ sigproc_printf ("args: %x, %d", what, val);
+
+ if (!get_proc_lock (what, val)) // Serialize access to this function
+ {
+ system_printf ("couldn't get proc lock. Something is wrong.");
+ 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)
+ {
+ rc = 0;
+ 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,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ 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->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)
+ {
+ 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 */
+ sync_proc_subproc->release (); // Release the lock ASAP
+ ForceCloseHandle1 (h, childhProc);
+ ProtectHandle1 (pchildren[val]->hProcess, childhProc);
+ rc = 0;
+ goto out; // This was an exec()
+ }
+
+ sigproc_printf ("pid %d[%d] terminated, handle %p, nchildren %d, nzombies %d",
+ pchildren[val]->pid, val, hchildren[val], nchildren, nzombies);
+
+ int thiszombie;
+ 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. */
+ if (nzombies >= NZOMBIES
+ || myself->getsig (SIGCHLD).sa_handler == (void *) SIG_IGN)
+ {
+ sigproc_printf ("automatically removing zombie %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
+ * 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 (!mychild (wval->pid))
+ goto out; // invalid pid. flag no such child
+
+ wval->status = 0; // Don't know status yet
+ sigproc_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);
+ w = waitq_head.next;
+ waitq_head.next = wval; /* Add at the beginning. */
+ wval->next = w; /* Link in rest of the list. */
+ 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)
+ sigproc_printf ("clear waiting threads");
+ else
+ sigproc_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)
+ sigproc_printf ("released waiting thread");
+ else if (!clearing && !(w->next->options & WNOHANG) && potential_match < 0)
+ sigproc_printf ("only found non-terminated children");
+ else if (potential_match <= 0) // nothing matched
+ {
+ sigproc_printf ("waiting thread found no children");
+ HANDLE oldw = w->next->ev;
+ w->next->pid = 0;
+ if (clearing)
+ w->next->status = -1; /* flag that a signal was received */
+ else if (!potential_match || !(w->next->options & WNOHANG))
+ 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)
+ sigproc_printf ("finished processing terminated/stopped child");
+ else
+ {
+ waitq_head.next = NULL;
+ sigproc_printf ("finished clearing");
+ }
+ break;
+ }
+
+out:
+ sync_proc_subproc->release (); // Release the lock
+out1:
+ sigproc_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)
+{
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+ /* Signal processing is assumed to be blocked in this routine. */
+ if (hwait_subproc)
+ {
+ 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. */
+ int i;
+ for (i = 0; i < nzombies; 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
+ }
+
+ /* 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;
+ /* Just zero sync_proc_subproc as the delete below seems to cause
+ problems for older gccs. */
+ sync_proc_subproc = NULL;
+ }
+ sigproc_printf ("leaving");
+}
+
+/* Clear pending signal from the sigtodo array
+ */
+void __stdcall
+sig_clear (int sig)
+{
+ (void) InterlockedExchange (myself->getsigtodo (sig), 0L);
+ (void) InterlockedExchange (getlocal_sigtodo (sig), 0L);
+ return;
+}
+
+extern "C" int
+sigpending (sigset_t *set)
+{
+ unsigned bit;
+ *set = 0;
+ for (int sig = 1; sig < NSIG; sig++)
+ if ((*getlocal_sigtodo (sig) || *myself->getsigtodo (sig))
+ && (myself->getsigmask () & (bit = SIGTOMASK (sig))))
+ *set |= bit;
+ return 0;
+}
+
+/* Force the wait_sig thread to wake up and scan the sigtodo array.
+ */
+extern "C" int __stdcall
+sig_dispatch_pending ()
+{
+ if (exit_state || !hwait_sig || GetCurrentThreadId () == sigtid)
+ return 0;
+
+ sigframe thisframe (mainthread);
+
+#ifdef DEBUGGING
+ sigproc_printf ("pending_signals %d", pending_signals);
+#endif
+
+ if (!pending_signals)
+#ifdef DEBUGGING
+ sigproc_printf ("no need to wake anything up");
+#else
+ ;
+#endif
+ else
+ {
+ (void) sig_send (myself, __SIGFLUSH);
+#ifdef DEBUGGING
+ sigproc_printf ("woke up wait_sig");
+#endif
+ }
+
+ return thisframe.call_signal_handler ();
+}
+
+/* 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, TRUE, FALSE, NULL);
+ ProtectHandle (wait_sig_inited);
+
+ /* sync_proc_subproc is used by proc_subproc. It serialises
+ * access to the children and zombie arrays.
+ */
+ new_muto (sync_proc_subproc);
+
+ /* local event signaled when main thread has been dispatched
+ to a signal handler function. */
+ signal_arrived = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
+ ProtectHandle (signal_arrived);
+
+ hwait_sig = new cygthread (wait_sig, cygself, "sig");
+ hwait_sig->zap_h ();
+
+ /* 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
+
+ myself->getsig (SIGSTOP).sa_flags = SA_RESTART | SA_NODEFER;
+ sigproc_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)
+{
+ hwait_sig = NULL;
+
+ if (!sig_loop_wait)
+ sigproc_printf ("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
+ 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
+
+ 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, bool exception)
+{
+ int rc = 1;
+ DWORD tid = GetCurrentThreadId ();
+ BOOL its_me;
+ HANDLE thiscatch = NULL;
+ HANDLE thiscomplete = NULL;
+ BOOL wait_for_completion;
+ sigframe thisframe;
+
+ if (p == myself_nowait_nonmain)
+ p = (tid == mainthread.id) ? (_pinfo *) 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
+ if (wait_sig_inited)
+ wait_for_sigthread ();
+ 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? */
+ {
+ sigproc_printf ("invalid pid %d(%x), signal %d",
+ p->pid, p->process_state, sig);
+ set_errno (ESRCH);
+ goto out;
+ }
+
+ sigproc_printf ("pid %d, signal %d, its_me %d", p->pid, sig, its_me);
+
+ LONG *todo;
+ bool issem;
+ if (its_me)
+ {
+ if (!wait_for_completion)
+ {
+ thiscatch = sigcatch_nosync;
+ todo = myself->getsigtodo (sig);
+ issem = false;
+ }
+ else if (tid != mainthread.id)
+ {
+ thiscatch = sigcatch_nonmain;
+ thiscomplete = sigcomplete_nonmain;
+ todo = getlocal_sigtodo (sig);
+ issem = true;
+ }
+ else
+ {
+ thiscatch = sigcatch_main;
+ thiscomplete = sigcomplete_main;
+ thisframe.init (mainthread, ebp, exception);
+ todo = getlocal_sigtodo (sig);
+ issem = true;
+ }
+ }
+ else if ((thiscatch = getevent (p, "sigcatch")))
+ {
+ todo = p->getsigtodo (sig);
+ issem = false;
+ }
+ else
+ goto out; // Couldn't get the semaphore. getevent 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 (todo);
+
+ /* Notify the process that a signal has arrived.
+ */
+ if (issem ? !ReleaseSemaphore (thiscatch, 1, NULL) : !SetEvent (thiscatch))
+ {
+ /* Couldn't signal the semaphore. This probably means that the
+ * process is exiting.
+ */
+ if (!its_me)
+ ForceCloseHandle (thiscatch);
+ else
+ {
+ if (no_signals_available ())
+ sigproc_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;
+ }
+
+ /* 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;
+ sigproc_printf ("Not waiting for sigcomplete. its_me %d signal %d", its_me, sig);
+ if (!its_me)
+ ForceCloseHandle (thiscatch);
+ }
+ else
+ {
+ sigproc_printf ("Waiting for thiscomplete %p", thiscomplete);
+ rc = WaitForSingleObject (thiscomplete, WSSC);
+ }
+
+ 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, signal %d, rc %d, %E",
+ sig, rc);
+ set_errno (ENOSYS);
+ rc = -1;
+ }
+
+out:
+ sigproc_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 (getlocal_sigtodo (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);
+ 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. */
+
+void __stdcall
+init_child_info (DWORD chtype, child_info *ch, pid_t pid, HANDLE subproc_ready)
+{
+ memset (ch, 0, sizeof *ch);
+ ch->cb = chtype == PROC_FORK ? sizeof (child_info_fork) : sizeof (child_info);
+ ch->intro = PROC_MAGIC_GENERIC;
+ ch->magic = CHILD_INFO_MAGIC;
+ ch->type = chtype;
+ ch->cygpid = pid;
+ ch->subproc_ready = subproc_ready;
+ ch->pppid_handle = myself->ppid_handle;
+ ch->fhandler_union_cb = sizeof (fhandler_union);
+ ch->mount_h = cygwin_mount_h;
+}
+
+/* Check the state of all of our children to see if any are stopped or
+ * terminated.
+ */
+static int __stdcall
+checkstate (waitq *parent_w)
+{
+ int potential_match = 0;
+
+ sigproc_printf ("nchildren %d, nzombies %d", nchildren, nzombies);
+
+ /* 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]))
+ {
+ case -1:
+ potential_match = -1;
+ break;
+ case 1:
+ remove_zombie (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;
+ }
+
+out:
+ sigproc_printf ("returning %d", potential_match);
+ return potential_match;
+}
+
+/* Get or create a process specific semaphore used in message passing.
+ */
+static HANDLE __stdcall
+getevent (_pinfo *p, const char *str)
+{
+ HANDLE h;
+ char sem_name[MAX_PATH];
+
+ if (p != NULL)
+ {
+ if (!proc_can_be_signalled (p))
+ {
+ set_errno (ESRCH);
+ return NULL;
+ }
+ int wait = 1000;
+ /* Wait for new process to generate its semaphores. */
+ sigproc_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++)
+ low_priority_sleep (1);
+ }
+
+ if (p == NULL)
+ {
+ char sa_buf[1024];
+
+ DWORD winpid = GetCurrentProcessId ();
+#if 0
+ h = CreateSemaphore (sec_user_nih (sa_buf), init, max,
+ str = shared_name (sem_name, str, winpid));
+#else
+ h = CreateEvent (sec_user_nih (sa_buf), FALSE, FALSE,
+ str = shared_name (sem_name, str, winpid));
+#endif
+ p = myself;
+ if (!h)
+ {
+ system_printf ("can't create semaphore %s, %E", str);
+ __seterrno ();
+ }
+ }
+ else
+ {
+#if 0
+ h = OpenSemaphore (SEMAPHORE_ALL_ACCESS, FALSE,
+ shared_name (sem_name, str, p->dwProcessId));
+#else
+ h = OpenEvent (EVENT_ALL_ACCESS, FALSE,
+ shared_name (sem_name, str, p->dwProcessId));
+#endif
+
+ if (!h)
+ {
+ if (GetLastError () == ERROR_FILE_NOT_FOUND && !proc_exists (p))
+ set_errno (ESRCH); /* No such process */
+ else
+ set_errno (EPERM); /* Couldn't access the semaphore --
+ different cygwin DLL maybe? */
+ }
+ }
+
+ return h;
+}
+
+/* Remove a zombie from zombies by swapping it with the last child in the list.
+ */
+static void __stdcall
+remove_zombie (int ci)
+{
+ sigproc_printf ("removing %d, pid %d, nzombies %d", ci, zombies[ci]->pid,
+ nzombies);
+
+ if (zombies[ci])
+ {
+ ForceCloseHandle1 (zombies[ci]->hProcess, childhProc);
+ ForceCloseHandle1 (zombies[ci]->pid_handle, pid_handle);
+ zombies[ci].release ();
+ }
+
+ 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;
+
+ sigproc_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)
+ {
+ 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 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;
+}
+
+static void
+talktome ()
+{
+ winpids pids;
+ for (unsigned i = 0; i < pids.npids; i++)
+ if (pids[i]->hello_pid == myself->pid)
+ pids[i]->commune_recv ();
+}
+
+#define RC_MAIN 0
+#define RC_NONMAIN 1
+#define RC_NOSYNC 2
+/* 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 *self)
+{
+ LONG *todos[] = {getlocal_sigtodo (0), myself->getsigtodo (0)};
+ /* Initialization */
+ (void) SetThreadPriority (GetCurrentThread (), 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 = getevent (NULL, "sigcatch");
+ 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_main %p", sigcatch_nonmain, sigcatch_main);
+ sigCONT = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL);
+
+ /* 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");
+ 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 ();
+
+ HANDLE catchem[] = {sigcatch_main, sigcatch_nonmain, sigcatch_nosync};
+ sigproc_printf ("Ready. dwProcessid %d", myself->dwProcessId);
+ DWORD rc = RC_NOSYNC;
+ bool flush = false;
+ for (;;)
+ {
+ DWORD i;
+ if (rc == RC_MAIN || rc == RC_NONMAIN)
+ i = RC_NOSYNC;
+ else
+ i = RC_MAIN;
+ rc = WaitForSingleObject (catchem[i], 0);
+ if (rc != WAIT_OBJECT_0)
+ rc = WaitForMultipleObjects (3, catchem, FALSE, sig_loop_wait);
+ else
+ rc = i + WAIT_OBJECT_0;
+ (void) SetThreadPriority (GetCurrentThread (), WAIT_SIG_PRIORITY);
+
+ /* 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;
+ sigproc_printf ("awake, rc %d", rc);
+ LONG *todo;
+ if (rc != RC_NOSYNC)
+ todo = todos[0];
+ else
+ todo = todos[1];
+
+ /* A sigcatch semaphore has been signaled. Scan the sigtodo
+ array looking for any unprocessed signals. */
+ pending_signals = false;
+ unsigned more_signals = 0;
+ bool saw_failed_interrupt = false;
+ do
+ {
+ more_signals = 0;
+ for (int sig = -__SIGOFFSET; sig < NSIG; sig++)
+ {
+ LONG x = InterlockedDecrement (todo + sig);
+ if (x < 0)
+ InterlockedIncrement (todo + sig);
+ else if (x >= 0)
+ {
+ /* If x > 0, we have to deal with a signal at some later point */
+ if (rc != RC_NOSYNC && x > 0)
+ /*pending_signals = true*/; // There should be an armed semaphore, in this case
+
+ if (sig > 0 && sig != SIGKILL && sig != SIGSTOP &&
+ (sigismember (&myself->getsigmask (), sig) ||
+ main_vfork->pid ||
+ (sig != SIGCONT && ISSTATE (myself, PID_STOPPED))))
+ {
+ sigproc_printf ("signal %d blocked", sig);
+ x = InterlockedIncrement (myself->getsigtodo (sig));
+ /* pending_signals = true;*/ // will be set by set_process_mask
+ }
+ else
+ {
+ sigproc_printf ("processing signal %d", sig);
+ switch (sig)
+ {
+ case __SIGFLUSH:
+ if (rc == RC_MAIN)
+ {
+ flush = true;
+ SetEvent (sigcatch_nosync);
+ goto out1;
+ }
+ break;
+
+ /* Internal signal to turn on stracing. */
+ case __SIGSTRACE:
+ strace.hello ();
+ break;
+
+ case __SIGCOMMUNE:
+ talktome ();
+ break;
+
+ /* A normal UNIX signal */
+ default:
+ sigproc_printf ("Got signal %d", sig);
+ if (!sig_handle (sig))
+ {
+ pending_signals = true;
+ saw_failed_interrupt = true;
+ x = InterlockedIncrement (myself->getsigtodo (sig));
+ }
+ }
+ if (rc == RC_NOSYNC && x > 0)
+ more_signals++;
+ }
+
+ if (sig == SIGCHLD)
+ proc_subproc (PROC_CLEARWAIT, 0);
+
+ /* Need to take special action if an interrupt failed due to main thread not
+ getting around to calling handler yet. */
+ if (saw_failed_interrupt || rc != RC_NOSYNC)
+ goto out;
+ }
+ }
+#ifdef DEBUGGING
+ if (more_signals > 100)
+ system_printf ("hmm. infinite loop? more_signals %u\n", more_signals);
+#endif
+ }
+ while (more_signals && sig_loop_wait);
+
+ out:
+ /* Signal completion of signal handling depending on which semaphore
+ woke up the WaitForMultipleObjects above. */
+ if (rc == RC_NONMAIN) // FIXME: This is broken
+ ReleaseSemaphore (sigcomplete_nonmain, 1, NULL);
+ else if (rc == RC_MAIN || flush)
+ {
+ SetEvent (sigcomplete_main);
+ sigproc_printf ("set main thread completion event");
+ flush = false;
+ }
+
+ out1:
+ if (saw_failed_interrupt)
+ {
+ SetEvent (sigcatch_nosync);
+ low_priority_sleep (0); /* Hopefully, other thread will be waking up soon. */
+ }
+ sigproc_printf ("looping");
+ }
+
+ 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 (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++)
+ 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)
+ {
+ rc = proc_subproc (PROC_CHILDTERMINATED, rc);
+ if (!proc_loop_wait) // Don't bother if wait_subproc is
+ break; // exiting
+
+ /* 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, SIGCHLD);
+ }
+ sigproc_printf ("looping");
+ }
+
+ ForceCloseHandle (events[0]);
+ events[0] = NULL;
+ sigproc_printf ("done");
+ ExitThread (0);
+}
+
+extern "C" {
+/* Provide a stack frame when calling WaitFor* functions */
+
+#undef WaitForSingleObject
+
+DWORD __stdcall
+WFSO (HANDLE hHandle, DWORD dwMilliseconds)
+{
+ DWORD ret;
+ sigframe thisframe (mainthread);
+ ret = WaitForSingleObject (hHandle, dwMilliseconds);
+ return ret;
+}
+
+#undef WaitForMultipleObjects
+
+DWORD __stdcall
+WFMO (DWORD nCount, CONST HANDLE *lpHandles, BOOL fWaitAll, DWORD dwMilliseconds)
+{
+ DWORD ret;
+ sigframe thisframe (mainthread);
+ ret = WaitForMultipleObjects (nCount, lpHandles, fWaitAll, dwMilliseconds);
+ return ret;
+}
+}
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
new file mode 100644
index 00000000000..369f3ac8575
--- /dev/null
+++ b/winsup/cygwin/winsup.h
@@ -0,0 +1,334 @@
+/* winsup.h: main Cygwin header file.
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+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. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define __INSIDE_CYGWIN__
+
+#define strlen __builtin_strlen
+#define strcmp __builtin_strcmp
+#define strcpy __builtin_strcpy
+#define memcpy __builtin_memcpy
+#define memcmp __builtin_memcmp
+#ifdef HAVE_BUILTIN_MEMSET
+# define memset __builtin_memset
+#endif
+
+#define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
+#define NO_COPY_INIT __attribute__((section(".data_cygwin_nocopy")))
+
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
+#define NEW_MACRO_VARARGS
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include <sys/types.h>
+#include <sys/strace.h>
+
+/* Declarations for functions used in C and C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern __uid32_t getuid32 (void);
+extern __uid32_t geteuid32 (void);
+extern int seteuid32 (__uid32_t);
+extern __gid32_t getegid32 (void);
+extern struct passwd *getpwuid32 (__uid32_t);
+extern struct passwd *getpwnam (const char *);
+extern struct __sFILE64 *fopen64 (const char *, const char *);
+extern struct hostent *cygwin_gethostbyname (const char *name);
+extern unsigned long cygwin_inet_addr (const char *cp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+
+extern const char case_folded_lower[];
+#define cyg_tolower(c) (case_folded_lower[(unsigned char)(c)])
+extern const char case_folded_upper[];
+#define cyg_toupper(c) (case_folded_upper[(unsigned char)(c)])
+
+#ifndef MALLOC_DEBUG
+#define cfree newlib_cfree_dont_use
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#define _WINGDI_H
+#define _WINUSER_H
+#define _WINNLS_H
+#define _WINVER_H
+#define _WINNETWK_H
+#define _WINSVC_H
+#include <windows.h>
+#include <wincrypt.h>
+#include <lmcons.h>
+#undef _WINGDI_H
+#undef _WINUSER_H
+#undef _WINNLS_H
+#undef _WINVER_H
+#undef _WINNETWK_H
+#undef _WINSVC_H
+
+#include "wincap.h"
+
+/* The one function we use from winuser.h most of the time */
+extern "C" DWORD WINAPI GetLastError (void);
+
+enum codepage_type {ansi_cp, oem_cp};
+extern codepage_type current_codepage;
+
+UINT get_cp ();
+
+int __stdcall sys_wcstombs(char *, const WCHAR *, int)
+ __attribute__ ((regparm(3)));
+
+int __stdcall sys_mbstowcs(WCHAR *, const char *, int)
+ __attribute__ ((regparm(3)));
+
+/* Used to check if Cygwin DLL is dynamically loaded. */
+extern int dynamically_loaded;
+
+extern int cygserver_running;
+
+#define _MT_SAFE // DELTEME someday
+
+#define TITLESIZE 1024
+
+/* status bit manipulation */
+#define __ISSETF(what, x, prefix) \
+ ((what)->status & prefix##_##x)
+#define __SETF(what, x, prefix) \
+ ((what)->status |= prefix##_##x)
+#define __CLEARF(what, x, prefix) \
+ ((what)->status &= ~prefix##_##x)
+#define __CONDSETF(n, what, x, prefix) \
+ ((n) ? __SETF (what, x, prefix) : __CLEARF (what, x, prefix))
+
+#include "debug.h"
+
+/* Events/mutexes */
+extern HANDLE title_mutex;
+
+/**************************** Convenience ******************************/
+
+/* Used when treating / and \ as equivalent. */
+#define isdirsep(ch) \
+ ({ \
+ char __c = (ch); \
+ ((__c) == '/' || (__c) == '\\'); \
+ })
+
+/* Convert a signal to a signal mask */
+#define SIGTOMASK(sig) (1<<((sig) - signal_shift_subtract))
+extern unsigned int signal_shift_subtract;
+
+#ifdef NEW_MACRO_VARARGS
+# define api_fatal(...) __api_fatal ("%P: *** " __VA_ARGS__)
+#else
+# define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args)
+#endif
+
+#undef issep
+#define issep(ch) (strchr (" \t\n\r", (ch)) != NULL)
+
+#define isabspath(p) \
+ (isdirsep (*(p)) || (isalpha (*(p)) && (p)[1] == ':' && (!(p)[2] || isdirsep ((p)[2]))))
+
+/******************** Initialization/Termination **********************/
+
+class per_process;
+/* cygwin .dll initialization */
+void dll_crt0 (per_process *) __asm__ ("_dll_crt0__FP11per_process");
+extern "C" void __stdcall _dll_crt0 ();
+
+/* dynamically loaded dll initialization */
+extern "C" int dll_dllcrt0 (HMODULE, per_process *);
+
+/* dynamically loaded dll initialization for non-cygwin apps */
+extern "C" int dll_noncygwin_dllcrt0 (HMODULE, per_process *);
+
+/* exit the program */
+
+enum exit_states
+ {
+ ES_NOT_EXITING = 0,
+ ES_EVENTS_TERMINATE,
+ ES_THREADTERM,
+ ES_SIGNAL,
+ ES_CLOSEALL,
+ ES_SIGPROCTERMINATE,
+ ES_TITLE,
+ ES_HUP_PGRP,
+ ES_HUP_SID,
+ ES_TTY_TERMINATE
+ };
+
+extern exit_states exit_state;
+void __stdcall do_exit (int) __attribute__ ((regparm (1), noreturn));
+
+/* UID/GID */
+void uinfo_init (void);
+
+#define ILLEGAL_UID16 ((__uid16_t)-1)
+#define ILLEGAL_UID ((__uid32_t)-1)
+#define ILLEGAL_GID16 ((__gid16_t)-1)
+#define ILLEGAL_GID ((__gid32_t)-1)
+#define ILLEGAL_SEEK ((_off64_t)-1)
+
+#define uid16touid32(u16) ((u16)==ILLEGAL_UID16?ILLEGAL_UID:(__uid32_t)(u16))
+#define gid16togid32(g16) ((g16)==ILLEGAL_GID16?ILLEGAL_GID:(__gid32_t)(g16))
+
+/* various events */
+void events_init (void);
+void events_terminate (void);
+
+void __stdcall close_all_files (void);
+
+/* Invisible window initialization/termination. */
+HWND __stdcall gethwnd (void);
+
+/* Globals that handle initialization of winsock in a child process. */
+extern HANDLE wsock32_handle;
+extern HANDLE ws2_32_handle;
+
+/* Globals that handle initialization of netapi in a child process. */
+extern HANDLE netapi32_handle;
+
+/* debug_on_trap support. see exceptions.cc:try_to_debug() */
+extern "C" void error_start_init (const char*);
+extern "C" int try_to_debug (bool waitloop = 1);
+
+void set_file_api_mode (codepage_type);
+
+extern int cygwin_finished_initializing;
+
+/**************************** Miscellaneous ******************************/
+
+void __stdcall set_std_handle (int);
+int __stdcall writable_directory (const char *file);
+int __stdcall stat_dev (DWORD, int, unsigned long, struct __stat64 *);
+
+__ino64_t __stdcall hash_path_name (__ino64_t hash, const char *name) __attribute__ ((regparm(2)));
+void __stdcall nofinalslash (const char *src, char *dst) __attribute__ ((regparm(2)));
+extern "C" char *__stdcall rootdir (char *full_path) __attribute__ ((regparm(1)));
+
+/* String manipulation */
+extern "C" char *__stdcall strccpy (char *s1, const char **s2, char c);
+extern "C" int __stdcall strcasematch (const char *s1, const char *s2) __attribute__ ((regparm(2)));
+extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3)));
+extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2)));
+
+/* Time related */
+void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag);
+long __stdcall to_time_t (FILETIME * ptr);
+void __stdcall to_timestruc_t (FILETIME * ptr, timestruc_t * out);
+void __stdcall time_as_timestruc_t (timestruc_t * out);
+
+void __stdcall set_console_title (char *);
+void init_console_handler ();
+void init_global_security ();
+
+int __stdcall check_null_str (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_empty_str (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_empty_str_errno (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_str_errno (const char *name) __attribute__ ((regparm(1)));
+int __stdcall __check_null_invalid_struct (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_null_invalid_struct_errno (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_invalid_read_ptr_errno (const void *s, unsigned sz) __attribute__ ((regparm(2)));
+
+#define check_null_invalid_struct(s) \
+ __check_null_invalid_struct ((s), sizeof (*(s)))
+#define check_null_invalid_struct_errno(s) \
+ __check_null_invalid_struct_errno ((s), sizeof (*(s)))
+
+struct iovec;
+ssize_t check_iovec_for_read (const struct iovec *, int) __attribute__ ((regparm(2)));
+ssize_t check_iovec_for_write (const struct iovec *, int) __attribute__ ((regparm(2)));
+
+#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
+void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
+
+extern bool wsock_started;
+
+/* Printf type functions */
+extern "C" void __api_fatal (const char *, ...) __attribute__ ((noreturn));
+extern "C" int __small_sprintf (char *dst, const char *fmt, ...) /*__attribute__ ((regparm (2)))*/;
+extern "C" int __small_vsprintf (char *dst, const char *fmt, va_list ap) /*__attribute__ ((regparm (3)))*/;
+extern void multiple_cygwin_problem (const char *, unsigned, unsigned);
+
+class path_conv;
+int __stdcall stat_worker (const char *name, struct __stat64 *buf, int nofollow,
+ path_conv *pc = NULL) __attribute__ ((regparm (3)));
+int __stdcall low_priority_sleep (DWORD) __attribute__ ((regparm (1)));
+#define SLEEP_0_STAY_LOW INFINITE
+
+/**************************** Exports ******************************/
+
+extern "C" {
+int cygwin_select (int , fd_set *, fd_set *, fd_set *,
+ struct timeval *to);
+int cygwin_gethostname (char *__name, size_t __len);
+
+int kill_pgrp (pid_t, int);
+int _kill (int, int);
+int _raise (int sig);
+
+extern DWORD binmode;
+extern char _data_start__, _data_end__, _bss_start__, _bss_end__;
+extern void (*__CTOR_LIST__) (void);
+extern void (*__DTOR_LIST__) (void);
+extern SYSTEM_INFO system_info;
+};
+
+/*************************** Unsorted ******************************/
+
+#define WM_ASYNCIO 0x8000 // WM_APP
+
+/* Note that MAX_PATH is defined in the windows headers */
+/* There is also PATH_MAX and MAXPATHLEN.
+ PATH_MAX is from Posix and does *not* include the trailing NUL.
+ MAXPATHLEN is from Unix.
+
+ Thou shalt use MAX_PATH throughout. It avoids the NUL vs no-NUL
+ issue and is neither of the Unixy ones [so we can punt on which
+ one is the right one to use]. */
+
+#define STD_RBITS (S_IRUSR | S_IRGRP | S_IROTH)
+#define STD_WBITS (S_IWUSR)
+#define STD_XBITS (S_IXUSR | S_IXGRP | S_IXOTH)
+#define NO_W ~(S_IWUSR | S_IWGRP | S_IWOTH)
+#define NO_R ~(S_IRUSR | S_IRGRP | S_IROTH)
+#define NO_X ~(S_IXUSR | S_IXGRP | S_IXOTH)
+
+/* The title on program start. */
+extern char *old_title;
+extern bool display_title;
+
+extern HANDLE hMainThread;
+extern HANDLE hMainProc;
+
+extern bool cygwin_testing;
+extern unsigned _cygwin_testing_magic;
+extern HMODULE cygwin_hmodule;
+
+extern char almost_null[];
+
+#define winsock2_active (wsadata.wVersion >= 512)
+#define winsock_active (wsadata.wVersion < 512)
+extern struct WSAData wsadata;
+
+#endif /* defined __cplusplus */