* cygtls.h (_cygtls::signal_exit): Delete from class.

* exception.h (cygwin_exception): New class.
(cygwin_exception::dumpstack): Declare new function.
(cygwin_exception::context): Ditto.
(cygwin_exception::dump_exception): Ditto.
* exceptions.cc (cygwin_exception::dump_exception): Move into cygwin_exception
class.  Accommodate new variable names.
(cygwin_exception::dumpstack): Ditto stackdump -> dumpstack.
(exception::handle): Move andreas processing earlier.  Defer signal processing
decisions to the signal thread where they belong.  Pass exception information
to sig_send via new siginfo_t si_cyg field.
(ctrl_c_handler): Wait for SIGHUP signal to be processed since it could cause a
process exit and we don't want races with thread exit lock.
(signal_exit): Move back here from sigproc.cc.  Modify arguments and remove
from sigpacket class.  Decide when to dump core based on signal type.
(sigpacket::process): Handle exiting signals in context of threads rather than
in the signal thread.  Signal debugger on non-Windows signals.  Remove
setup_signal_exit call.
* sigproc.cc (no_signals_available): Remove argument.
(signal_exit_code): Delete.
(close_my_readsig): Ditto.
(_cygtls::signal_exit): Move to exceptions.cc.
(sigproc_terminate): Don't attempt to terminate signal thread.
(setup_signal_exit): Delete.
(exit_thread): Use new si_cyg entry in siginfo_t.
(sig_send): Just use empty initializer for si.  Accommodate change in
no_signals_available argument.
(wait_sig): Remove attempt to "go asynchronous" on process exit.  Delete
__SIGEXIT handling.  Don't ever exit.
* sigproc.h: Remove __SIGEXIT from signal enum.  Renumber.
* include/cygwin/signal.h (siginfo_t): Add si_cyg entry.
This commit is contained in:
Christopher Faylor
2013-01-02 18:34:06 +00:00
parent 74f8546d6e
commit ca77b848e7
8 changed files with 3264 additions and 3282 deletions

View File

@ -1,7 +1,7 @@
/* sigproc.cc: inter/intra signal and sub process handler
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@ -31,7 +31,7 @@ details. */
#define WSSC 60000 // Wait for signal completion
#define WPSP 40000 // Wait for proc_subproc mutex
#define no_signals_available(x) (!my_sendsig || ((x) && myself->exitcode & EXITCODE_SET) || (&_my_tls == _sig_tls))
#define no_signals_available() (exit_state || (myself->exitcode & EXITCODE_SET) || (&_my_tls == _sig_tls))
/*
* Global variables
@ -61,7 +61,6 @@ _cygtls NO_COPY *_sig_tls;
Static HANDLE my_sendsig;
Static HANDLE my_readsig;
Static int signal_exit_code;
/* Function declarations */
static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
@ -354,53 +353,6 @@ _cygtls::remove_wq (DWORD wait)
}
}
inline void
close_my_readsig ()
{
HANDLE h;
if ((h = InterlockedExchangePointer (&my_readsig, NULL)))
ForceCloseHandle1 (h, my_readsig);
}
/* Exit due to a signal, even in presence of more exceptions. We used to just
call exit, but a SIGSEGV shouldn't cause atexit routines to run.
Should only be called from the signal thread. */
void
_cygtls::signal_exit (int rc)
{
signal_debugger (rc & 0x7f);
if (rc == SIGQUIT || rc == SIGABRT)
{
CONTEXT c;
c.ContextFlags = CONTEXT_FULL;
GetThreadContext (hMainThread, &c);
copy_context (&c);
if (cygheap->rlim_core > 0UL)
rc |= 0x80;
}
if (have_execed)
{
sigproc_printf ("terminating captive process");
TerminateProcess (ch_spawn, sigExeced = rc);
}
if ((rc & 0x80) && !try_to_debug ())
stackdump (thread_context.ebp, true);
lock_process until_exit (true);
if (have_execed || exit_state > ES_PROCESS_LOCKED)
myself.exit (rc);
/* Starve other threads in a vain attempt to stop them from doing something
stupid. */
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
sigproc_printf ("about to call do_exit (%x)", rc);
do_exit (rc);
}
/* Terminate the wait_subproc thread.
Called on process exit.
Also called by spawn_guts to disassociate any subprocesses from this
@ -523,36 +475,11 @@ sigproc_terminate (exit_states es)
exit_states prior_exit_state = exit_state;
exit_state = es;
if (!cygwin_finished_initializing)
sigproc_printf ("don't worry about signal thread");
/* nothing to do */;
else if (prior_exit_state >= ES_FINAL)
sigproc_printf ("already performed");
else
{
sigproc_printf ("entering");
sig_send (myself_nowait, __SIGEXIT);
proc_terminate (); // clean up process stuff
}
}
/* Set up stuff so that the signal thread will know that we are
exiting due to a signal. */
void
setup_signal_exit (int sig)
{
signal_exit_code = sig; /* Tell wait_sig() that we are exiting. */
exit_state = ES_SIGNAL_EXIT; /* Tell the rest of the world that we are exiting. */
if (&_my_tls != _sig_tls)
{
sigpacket sp = {};
sp.si.si_signo = __SIGEXIT;
DWORD len;
/* Write a packet to the wait_sig thread. It will eventuall cause
the process to exit too. So just wait for that to happen after
sending the packet. */
WriteFile (my_sendsig, &sp, sizeof (sp), &len, NULL);
Sleep (INFINITE);
}
proc_terminate (); // clean up process stuff
}
/* Exit the current thread very carefully.
@ -576,7 +503,7 @@ exit_thread (DWORD res)
}
ProtectHandle1 (h, exit_thread);
siginfo_t si = {__SIGTHREADEXIT, SI_KERNEL};
si.si_value.sival_ptr = h;
si.si_cyg = h;
lock_process for_now; /* May block indefinitely if we're exiting. */
if (exit_state)
{
@ -599,7 +526,7 @@ sig_send (_pinfo *p, int sig, _cygtls *tid)
/* nothing */;
else if (sig == __SIGFLUSH || sig == __SIGFLUSHFAST)
return 0;
else if (sig == __SIGNOHOLD || sig == __SIGEXIT)
else if (sig == __SIGNOHOLD)
{
SetEvent (sig_hold);
sigheld = false;
@ -611,10 +538,9 @@ sig_send (_pinfo *p, int sig, _cygtls *tid)
#endif
return -1;
}
siginfo_t si = {0};
siginfo_t si = {};
si.si_signo = sig;
si.si_code = SI_KERNEL;
si.si_pid = si.si_uid = si.si_errno = 0;
return sig_send (p, si, tid);
}
@ -648,7 +574,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
}
else
{
if (no_signals_available (si.si_signo != __SIGEXIT))
if (no_signals_available ())
{
set_errno (EAGAIN);
goto out; // Either exiting or not yet initializing
@ -778,7 +704,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
}
else
{
if (no_signals_available (true))
if (no_signals_available ())
sigproc_printf ("I'm going away now");
else if (!p->exec_sendsig)
system_printf ("error sending signal %d to pid %d, pipe handle %p, %E",
@ -818,7 +744,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
rc = 0; // Successful exit
else
{
if (!no_signals_available (true))
if (!no_signals_available ())
system_printf ("wait for sig_complete event failed, signal %d, rc %d, %E",
si.si_signo, rc);
set_errno (ENOSYS);
@ -1390,12 +1316,6 @@ wait_sig (VOID *)
WaitForSingleObject (sig_hold, INFINITE);
DWORD nb;
/* If signal_exit_code is set then we are shutting down due to a signal.
We'll exit this loop iff there is nothing more in the signal queue. */
if (signal_exit_code
&& (!PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) || !nb))
break;
pack.sigtls = NULL;
if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL))
break;
@ -1415,8 +1335,9 @@ wait_sig (VOID *)
continue;
}
if (signal_exit_code && pack.si.si_signo > 0)
continue; /* No more real signals allowed */
/* Don't process signals when we start exiting */
if (exit_state && pack.si.si_signo)
continue;
sigset_t dummy_mask;
if (!pack.mask)
@ -1459,10 +1380,6 @@ wait_sig (VOID *)
clearwait = true;
}
break;
case __SIGEXIT:
my_sendsig = NULL;
sigproc_printf ("saw __SIGEXIT");
break; /* handle below */
case __SIGSETPGRP:
init_console_handler (true);
break;
@ -1475,7 +1392,7 @@ wait_sig (VOID *)
release the process lock which it held and close it's handle.
See cgf-000017 in DevNotes for more details.
*/
HANDLE h = (HANDLE) pack.si.si_value.sival_ptr;
HANDLE h = (HANDLE) pack.si.si_cyg;
DWORD res = WaitForSingleObject (h, 5000);
lock_process::force_release (pack.sigtls);
ForceCloseHandle1 (h, exit_thread);
@ -1519,20 +1436,5 @@ wait_sig (VOID *)
sigproc_printf ("signalling pack.wakeup %p", pack.wakeup);
SetEvent (pack.wakeup);
}
if (pack.si.si_signo == __SIGEXIT)
break;
}
sigproc_printf ("signal thread exiting");
my_sendsig = NULL; /* Make no_signals_allowed return true */
close_my_readsig (); /* Cause any sig_send's to stop */
if (signal_exit_code)
_my_tls.signal_exit (signal_exit_code);
/* Just wait for the process to go away. Otherwise, this thread's
exit value could be interpreted as the process exit value.
See cgf-000017 in DevNotes for more details. */
Sleep (INFINITE);
}