* 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.
This commit is contained in:
Christopher Faylor
2013-04-09 01:01:19 +00:00
parent 037ad80a52
commit 9d2155089e
7 changed files with 156 additions and 141 deletions

View File

@ -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;