* 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

@ -1,3 +1,38 @@
2013-04-08 Christopher Faylor <me.cygwin2013@cgf.cx>
* 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.
2013-04-08 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (get_inet_addr): Handle abstract AF_LOCAL socket.

View File

@ -253,7 +253,13 @@ public:
will_wait_for_signal = true;
}
}
void reset_signal_arrived () { will_wait_for_signal = false; }
void reset_signal_arrived ()
{
if (signal_arrived)
ResetEvent (signal_arrived);
will_wait_for_signal = false;
}
void handle_SIGCONT ();
private:
void __reg3 call2 (DWORD (*) (void *, void *), void *, void *);
/*gentls_offsets*/

View File

@ -1,6 +1,6 @@
/* cygwait.h
Copyright 2011, 2012 Red Hat, Inc.
Copyright 2011, 2012, 2013 Red Hat, Inc.
This file is part of Cygwin.
@ -17,9 +17,9 @@
#define is_cw_cancel_self (mask & cw_cancel_self)
#define is_cw_sig (mask & cw_sig)
#define is_cw_sig_eintr (mask & cw_sig_eintr)
#define is_cw_sig_return (mask & cw_sig_return)
#define is_cw_sig_cont (mask & cw_sig_cont)
#define is_cw_sig_handle (mask & (is_cw_sig | is_cw_sig_eintr))
#define is_cw_sig_handle (mask & (cw_sig | cw_sig_eintr | cw_sig_cont))
LARGE_INTEGER cw_nowait_storage;
@ -83,10 +83,12 @@ cygwait (HANDLE object, PLARGE_INTEGER timeout, unsigned mask)
{
_my_tls.lock ();
int sig = _my_tls.sig;
if (is_cw_sig_cont && sig == SIGCONT)
_my_tls.sig = 0;
_my_tls.unlock ();
if (!sig)
continue;
if (is_cw_sig_eintr)
if (is_cw_sig_eintr || (is_cw_sig_cont && sig == SIGCONT))
res = WAIT_SIGNALED; /* caller will deal with signals */
else if (_my_tls.call_signal_handler ())
continue;

View File

@ -1,6 +1,6 @@
/* cygwait.h
Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
Red Hat, Inc.
This file is part of Cygwin.
@ -19,7 +19,8 @@ enum cw_wait_mask
cw_cancel = 0x0001,
cw_cancel_self = 0x0002,
cw_sig = 0x0004,
cw_sig_eintr = 0x0008
cw_sig_eintr = 0x0008,
cw_sig_cont = 0x0010
};
extern LARGE_INTEGER cw_nowait_storage;

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;

View File

@ -73,20 +73,15 @@ class pending_signals
{
sigpacket sigs[NSIG + 1];
sigpacket start;
sigpacket *end;
sigpacket *prev;
sigpacket *curr;
bool retry;
public:
void reset () {curr = &start; prev = &start;}
void add (sigpacket&);
void del ();
bool pending () {retry = true; return !!start.next;}
sigpacket *next ();
sigpacket *save () const {return curr;}
void restore (sigpacket *saved) {curr = saved;}
void clear (int sig) {sigs[sig].si.si_signo = 0;}
friend void __reg1 sig_dispatch_pending (bool);;
friend void WINAPI wait_sig (VOID *arg);
friend void sigproc_init ();
};
Static pending_signals sigq;
@ -338,18 +333,22 @@ out1:
void
_cygtls::remove_wq (DWORD wait)
{
if (exit_state < ES_FINAL && waitq_head.next && sync_proc_subproc
&& sync_proc_subproc.acquire (wait))
if (wq.thread_ev)
{
for (waitq *w = &waitq_head; w->next != NULL; w = w->next)
if (w->next == &wq)
{
ForceCloseHandle1 (wq.thread_ev, wq_ev);
w->next = wq.next;
break;
}
sync_proc_subproc.release ();
if (exit_state < ES_FINAL && waitq_head.next && sync_proc_subproc
&& sync_proc_subproc.acquire (wait))
{
for (waitq *w = &waitq_head; w->next != NULL; w = w->next)
if (w->next == &wq)
{
w->next = wq.next;
break;
}
sync_proc_subproc.release ();
}
ForceCloseHandle1 (wq.thread_ev, wq_ev);
}
}
/* Terminate the wait_subproc thread.
@ -392,23 +391,9 @@ proc_terminate ()
/* Clear pending signal */
void __reg1
sig_clear (int target_sig)
sig_clear (int sig)
{
if (&_my_tls != _sig_tls)
sig_send (myself, -target_sig);
else
{
sigpacket *q;
sigpacket *save = sigq.save ();
sigq.reset ();
while ((q = sigq.next ()))
if (q->si.si_signo == target_sig)
{
q->si.si_signo = __SIGDELETE;
break;
}
sigq.restore (save);
}
sigq.clear (sig);
}
extern "C" int
@ -425,21 +410,10 @@ sigpending (sigset_t *mask)
void __reg1
sig_dispatch_pending (bool fast)
{
if (&_my_tls == _sig_tls)
{
#ifdef DEBUGGING
sigproc_printf ("exit_state %d, cur thread id %p, _sig_tls %p, sigq.start.next %p",
exit_state, GetCurrentThreadId (), _sig_tls, sigq.start.next);
#endif
return;
}
/* Non-atomically test for any signals pending and wake up wait_sig if any are
found. It's ok if there's a race here since the next call to this function
should catch it.
FIXME: Eventually, wait_sig should wake up on its own to deal with pending
signals. */
if (sigq.pending ())
should catch it. */
if (sigq.pending () && &_my_tls != _sig_tls)
sig_send (myself, fast ? __SIGFLUSHFAST : __SIGFLUSH);
}
@ -728,7 +702,6 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls)
if (wait_for_completion && si.si_signo != __SIGFLUSHFAST)
_my_tls.call_signal_handler ();
goto out;
out:
if (communing && rc)
@ -1232,46 +1205,19 @@ talktome (siginfo_t *si)
new cygthread (commune_process, size, si, "commune");
}
/* Add a packet to the beginning of the queue.
Should only be called from signal thread. */
void
pending_signals::add (sigpacket& pack)
{
sigpacket *se;
se = sigs + pack.si.si_signo;
if (se->si.si_signo)
return;
*se = pack;
se->next = NULL;
if (end)
end->next = se;
end = se;
if (!start.next)
start.next = se;
}
void
pending_signals::del ()
{
sigpacket *next = curr->next;
prev->next = next;
curr->si.si_signo = 0;
#ifdef DEBUGGING
curr->next = NULL;
#endif
if (end == curr)
end = prev;
curr = next;
}
sigpacket *
pending_signals::next ()
{
sigpacket *res;
prev = curr;
if (!curr || !(curr = curr->next))
res = NULL;
else
res = curr;
return res;
start.next = se;
}
/* Process signals by waiting for signal data to arrive in a pipe.
@ -1311,7 +1257,7 @@ wait_sig (VOID *)
pack.mask = &dummy_mask;
}
sigpacket *q;
sigpacket *q = &sigq.start;
bool clearwait = false;
switch (pack.si.si_signo)
{
@ -1324,8 +1270,7 @@ wait_sig (VOID *)
case __SIGPENDING:
*pack.mask = 0;
unsigned bit;
sigq.reset ();
while ((q = sigq.next ()))
while ((q = q->next))
if (pack.sigtls->sigmask & (bit = SIGTOMASK (q->si.si_signo)))
*pack.mask |= bit;
break;
@ -1340,15 +1285,23 @@ wait_sig (VOID *)
case __SIGNOHOLD:
case __SIGFLUSH:
case __SIGFLUSHFAST:
sigq.reset ();
while ((q = sigq.next ()))
{
int sig = q->si.si_signo;
if (sig == __SIGDELETE || q->process () > 0)
sigq.del ();
if (sig == SIGCHLD)
clearwait = true;
}
{
sigpacket *qnext;
/* Check the queue for signals. There will always be at least one
thing on the queue if this was a valid signal. */
while ((qnext = q->next))
{
if (qnext->si.si_signo && qnext->process () <= 0)
q = q->next;
else
{
q->next = qnext->next;
qnext->si.si_signo = 0;
}
}
if (pack.si.si_signo == SIGCHLD)
clearwait = true;
}
break;
case __SIGSETPGRP:
init_console_handler (true);

View File

@ -20,7 +20,7 @@ enum
__SIGSTRACE = -(NSIG + 2),
__SIGCOMMUNE = -(NSIG + 3),
__SIGPENDING = -(NSIG + 4),
__SIGDELETE = -(NSIG + 5),
__SIGDELETE = -(NSIG + 5), /* Not currently used */
__SIGFLUSHFAST = -(NSIG + 6),
__SIGHOLD = -(NSIG + 7),
__SIGNOHOLD = -(NSIG + 8),