diff options
author | Christopher Faylor <me@cgf.cx> | 2013-04-09 01:01:19 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2013-04-09 01:01:19 +0000 |
commit | 9d2155089e8709977ef012cfdfd88d511b92d154 (patch) | |
tree | b2d6845c34da33952996e16a1e637f61268ae351 /winsup/cygwin/exceptions.cc | |
parent | 037ad80a525e5be3088bcb3b34546498695e746f (diff) | |
download | cygnal-9d2155089e8709977ef012cfdfd88d511b92d154.tar.gz cygnal-9d2155089e8709977ef012cfdfd88d511b92d154.tar.bz2 cygnal-9d2155089e8709977ef012cfdfd88d511b92d154.zip |
* cygtls.h (_cygtls::reset_signal_arrived): Actually reset the signal_arrived
event.
(_cygtls::handle_SIGCONT): Declare ew function.
* cygwait.cc (is_cw_sig_handle): Delete.
(is_cw_sig_cont): New convenience define.
(cygwait): Clear signal if is_cw_sig_cont and we got a SIGCONT.
* cygwait.h (cw_wait_mask): Add cw_sig_cont.
* exceptions.cc (sig_handle_tty_stop): Tighten "incyg" region. Use cw_sig_cont
param for cygwait. Don't zero signal here outside of lock.
(sigpacket::setup_handler): Don't check for in_forkee since we will now never
get here in that state.
(_cygtls::handle_SIGCONT): Define new function.
(sigpacket::process): Call handle_SIGCONT early to deal with SIGCONT. Nuke
continue_now handling. Allow SIGKILL to kill a suspended process. Delete a
couple of now-unneeded labels.
(_cygtls::call_signal_handler): Reorganize setting of incyg within lock.
* sigproc.cc (pending_signals): Simplify.
(pending_signals::clear): New method.
(_cygtls::remove_wq): Reorganize to always close wq.thread_ev if it exists to
avoid handle leaks.
(sig_clear): Simplify by just calling sigq.clear().
(sig_dispatch_pending): Always call sigq.pending even in signal thread to force
another loop in wait_sig.
(sig_send): Remove a "goto out" just before out: label.
(pending_signals::add): Simplify.
(pending_signals::del): Delete.
(pending_signals::next): Delete.
(wait_sig): Define variable q to be the start of the signal queue. Just
iterate through sigq queue, deleting processed or zeroed signals. Only set
clearwait when the current signal is SIGCHLD.
* sigproc.h: Add a comment about an unused enum.
Diffstat (limited to 'winsup/cygwin/exceptions.cc')
-rw-r--r-- | winsup/cygwin/exceptions.cc | 102 |
1 files changed, 60 insertions, 42 deletions
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 9815be280..d86635bae 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -686,23 +686,24 @@ extern "C" { static void sig_handle_tty_stop (int sig, siginfo_t *, void *) { - _my_tls.incyg = 1; /* Silently ignore attempts to suspend if there is no accommodating cygwin parent to deal with this behavior. */ if (!myself->cygstarted) myself->process_state &= ~PID_STOPPED; else { + _my_tls.incyg = 1; myself->stopsig = sig; myself->alert_parent (sig); sigproc_printf ("process %d stopped by signal %d", myself->pid, sig); /* FIXME! This does nothing to suspend anything other than the main thread. */ - DWORD res = cygwait (NULL, cw_infinite, cw_sig_eintr); + /* Use special cygwait parameter to handle SIGCONT. _main_tls.sig will + be cleared under lock when SIGCONT is detected. */ + DWORD res = cygwait (NULL, cw_infinite, cw_sig_cont); switch (res) { case WAIT_SIGNALED: - _my_tls.sig = 0; myself->stopsig = SIGCONT; myself->alert_parent (SIGCONT); break; @@ -710,8 +711,8 @@ sig_handle_tty_stop (int sig, siginfo_t *, void *) api_fatal ("WaitSingleObject returned %d", res); break; } + _my_tls.incyg = 0; } - _my_tls.incyg = 0; } } /* end extern "C" */ @@ -785,10 +786,6 @@ sigpacket::setup_handler (void *handler, struct sigaction& siga, _cygtls *tls) goto out; } - while (in_forkee) - yield (); /* Won't be able to send signals until we're finished - processing fork(). */ - for (int n = 0; n < CALL_HANDLER_RETRY_OUTER; n++) { for (int i = 0; i < CALL_HANDLER_RETRY_INNER; i++) @@ -1121,31 +1118,56 @@ signal_exit (int sig, siginfo_t *si) } } /* extern "C" */ +/* Attempt to carefully handle SIGCONT when we are stopped. */ +void +_cygtls::handle_SIGCONT () +{ + if (ISSTATE (myself, PID_STOPPED)) + { + myself->stopsig = 0; + myself->process_state &= ~PID_STOPPED; + int state = 0; + /* Carefully tell sig_handle_tty_stop to wake up. */ + while (state < 2) + { + lock (); + if (sig) + yield (); /* state <= 1 */ + else if (state) + state++; /* state == 2 */ + else + { + sig = SIGCONT; + SetEvent (signal_arrived); + state++; /* state == 1 */ + } + unlock (); + } + /* Tell wait_sig to handle any queued signals now that we're alive + again. */ + sig_dispatch_pending (false); + } + /* Clear pending stop signals */ + sig_clear (SIGSTOP); + sig_clear (SIGTSTP); + sig_clear (SIGTTIN); + sig_clear (SIGTTOU); +} + int __stdcall sigpacket::process () { int rc = 1; bool issig_wait = false; - bool continue_now = false; struct sigaction& thissig = global_sigs[si.si_signo]; void *handler = have_execed ? NULL : (void *) thissig.sa_handler; + /* Don't try to send signals if we're just starting up since signal masks + may not be available. */ if (!cygwin_finished_initializing) { rc = -1; - goto really_done; - } - - if (si.si_signo == SIGCONT) - { - continue_now = ISSTATE (myself, PID_STOPPED); - myself->stopsig = 0; - myself->process_state &= ~PID_STOPPED; - /* Clear pending stop signals */ - sig_clear (SIGSTOP); - sig_clear (SIGTSTP); - sig_clear (SIGTTIN); - sig_clear (SIGTTOU); + goto done; } sigproc_printf ("signal %d processing", si.si_signo); @@ -1153,7 +1175,17 @@ sigpacket::process () myself->rusage_self.ru_nsignals++; _cygtls *tls; - if (!sigtls) + if (si.si_signo == SIGCONT) + _main_tls->handle_SIGCONT (); + + if (si.si_signo == SIGKILL) + tls = _main_tls; /* SIGKILL is special. It always goes through. */ + else if (ISSTATE (myself, PID_STOPPED)) + { + rc = -1; /* Don't send signals when stopped */ + goto done; + } + else if (!sigtls) { tls = cygheap->find_tls (si.si_signo, issig_wait); sigproc_printf ("using tls %p", tls); @@ -1169,7 +1201,8 @@ sigpacket::process () tls = NULL; } - if (!tls || ISSTATE (myself, PID_STOPPED)) + /* !tls means no threads available to catch a signal. */ + if (!tls) { sigproc_printf ("signal %d blocked", si.si_signo); rc = -1; @@ -1225,6 +1258,7 @@ sigpacket::process () goto dosig; stop: + tls = _main_tls; handler = (void *) sig_handle_tty_stop; thissig = global_sigs[SIGSTOP]; goto dosig; @@ -1232,17 +1266,8 @@ stop: exit_sig: handler = (void *) signal_exit; thissig.sa_flags |= SA_SIGINFO; - if (si.si_signo == SIGKILL) - goto dispatch_sig; dosig: - if (ISSTATE (myself, PID_STOPPED) && !continue_now) - { - rc = -1; /* No signals delivered if stopped */ - goto done; - } - -dispatch_sig: if (have_execed) { sigproc_printf ("terminating captive process"); @@ -1251,15 +1276,8 @@ dispatch_sig: /* Dispatch to the appropriate function. */ sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler); rc = setup_handler (handler, thissig, tls); - continue_now = false; done: - if (continue_now) - { - (tls ?: _main_tls)->sig = SIGCONT; - SetEvent (tls->signal_arrived); - } -really_done: sigproc_printf ("returning %d", rc); return rc; @@ -1293,11 +1311,11 @@ _cygtls::call_signal_handler () sigset_t this_oldmask = set_process_mask_delta (); int this_errno = saved_errno; - sig = 0; /* Flag that we can accept another signal */ reset_signal_arrived (); + incyg = false; + sig = 0; /* Flag that we can accept another signal */ unlock (); /* unlock signal stack */ - incyg = false; /* no ucontext_t information provided yet, so third arg is NULL */ thisfunc (thissig, &thissi, NULL); incyg = true; |