Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/sigproc.cc')
-rw-r--r--winsup/cygwin/sigproc.cc1369
1 files changed, 0 insertions, 1369 deletions
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
deleted file mode 100644
index a9f7c17ac..000000000
--- a/winsup/cygwin/sigproc.cc
+++ /dev/null
@@ -1,1369 +0,0 @@
-/* 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;
- if (m)
- {
- 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;
-}