* 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:
@ -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;
|
||||
|
Reference in New Issue
Block a user