4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-22 16:49:45 +08:00

* 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> 2013-04-08 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (get_inet_addr): Handle abstract AF_LOCAL socket. * fhandler_socket.cc (get_inet_addr): Handle abstract AF_LOCAL socket.

View File

@ -253,7 +253,13 @@ public:
will_wait_for_signal = true; 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: private:
void __reg3 call2 (DWORD (*) (void *, void *), void *, void *); void __reg3 call2 (DWORD (*) (void *, void *), void *, void *);
/*gentls_offsets*/ /*gentls_offsets*/

View File

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

View File

@ -1,6 +1,6 @@
/* cygwait.h /* 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. Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -19,7 +19,8 @@ enum cw_wait_mask
cw_cancel = 0x0001, cw_cancel = 0x0001,
cw_cancel_self = 0x0002, cw_cancel_self = 0x0002,
cw_sig = 0x0004, cw_sig = 0x0004,
cw_sig_eintr = 0x0008 cw_sig_eintr = 0x0008,
cw_sig_cont = 0x0010
}; };
extern LARGE_INTEGER cw_nowait_storage; extern LARGE_INTEGER cw_nowait_storage;

View File

@ -686,23 +686,24 @@ extern "C" {
static void static void
sig_handle_tty_stop (int sig, siginfo_t *, void *) sig_handle_tty_stop (int sig, siginfo_t *, void *)
{ {
_my_tls.incyg = 1;
/* Silently ignore attempts to suspend if there is no accommodating /* Silently ignore attempts to suspend if there is no accommodating
cygwin parent to deal with this behavior. */ cygwin parent to deal with this behavior. */
if (!myself->cygstarted) if (!myself->cygstarted)
myself->process_state &= ~PID_STOPPED; myself->process_state &= ~PID_STOPPED;
else else
{ {
_my_tls.incyg = 1;
myself->stopsig = sig; myself->stopsig = sig;
myself->alert_parent (sig); myself->alert_parent (sig);
sigproc_printf ("process %d stopped by signal %d", myself->pid, sig); sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
/* FIXME! This does nothing to suspend anything other than the main /* FIXME! This does nothing to suspend anything other than the main
thread. */ 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) switch (res)
{ {
case WAIT_SIGNALED: case WAIT_SIGNALED:
_my_tls.sig = 0;
myself->stopsig = SIGCONT; myself->stopsig = SIGCONT;
myself->alert_parent (SIGCONT); myself->alert_parent (SIGCONT);
break; break;
@ -710,8 +711,8 @@ sig_handle_tty_stop (int sig, siginfo_t *, void *)
api_fatal ("WaitSingleObject returned %d", res); api_fatal ("WaitSingleObject returned %d", res);
break; break;
} }
}
_my_tls.incyg = 0; _my_tls.incyg = 0;
}
} }
} /* end extern "C" */ } /* end extern "C" */
@ -785,10 +786,6 @@ sigpacket::setup_handler (void *handler, struct sigaction& siga, _cygtls *tls)
goto out; 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 n = 0; n < CALL_HANDLER_RETRY_OUTER; n++)
{ {
for (int i = 0; i < CALL_HANDLER_RETRY_INNER; i++) for (int i = 0; i < CALL_HANDLER_RETRY_INNER; i++)
@ -1121,31 +1118,56 @@ signal_exit (int sig, siginfo_t *si)
} }
} /* extern "C" */ } /* extern "C" */
int __stdcall /* Attempt to carefully handle SIGCONT when we are stopped. */
sigpacket::process () void
_cygtls::handle_SIGCONT ()
{ {
int rc = 1; if (ISSTATE (myself, PID_STOPPED))
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;
if (!cygwin_finished_initializing)
{ {
rc = -1;
goto really_done;
}
if (si.si_signo == SIGCONT)
{
continue_now = ISSTATE (myself, PID_STOPPED);
myself->stopsig = 0; myself->stopsig = 0;
myself->process_state &= ~PID_STOPPED; 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 */ /* Clear pending stop signals */
sig_clear (SIGSTOP); sig_clear (SIGSTOP);
sig_clear (SIGTSTP); sig_clear (SIGTSTP);
sig_clear (SIGTTIN); sig_clear (SIGTTIN);
sig_clear (SIGTTOU); sig_clear (SIGTTOU);
}
int __stdcall
sigpacket::process ()
{
int rc = 1;
bool issig_wait = 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 done;
} }
sigproc_printf ("signal %d processing", si.si_signo); sigproc_printf ("signal %d processing", si.si_signo);
@ -1153,7 +1175,17 @@ sigpacket::process ()
myself->rusage_self.ru_nsignals++; myself->rusage_self.ru_nsignals++;
_cygtls *tls; _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); tls = cygheap->find_tls (si.si_signo, issig_wait);
sigproc_printf ("using tls %p", tls); sigproc_printf ("using tls %p", tls);
@ -1169,7 +1201,8 @@ sigpacket::process ()
tls = NULL; 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); sigproc_printf ("signal %d blocked", si.si_signo);
rc = -1; rc = -1;
@ -1225,6 +1258,7 @@ sigpacket::process ()
goto dosig; goto dosig;
stop: stop:
tls = _main_tls;
handler = (void *) sig_handle_tty_stop; handler = (void *) sig_handle_tty_stop;
thissig = global_sigs[SIGSTOP]; thissig = global_sigs[SIGSTOP];
goto dosig; goto dosig;
@ -1232,17 +1266,8 @@ stop:
exit_sig: exit_sig:
handler = (void *) signal_exit; handler = (void *) signal_exit;
thissig.sa_flags |= SA_SIGINFO; thissig.sa_flags |= SA_SIGINFO;
if (si.si_signo == SIGKILL)
goto dispatch_sig;
dosig: dosig:
if (ISSTATE (myself, PID_STOPPED) && !continue_now)
{
rc = -1; /* No signals delivered if stopped */
goto done;
}
dispatch_sig:
if (have_execed) if (have_execed)
{ {
sigproc_printf ("terminating captive process"); sigproc_printf ("terminating captive process");
@ -1251,15 +1276,8 @@ dispatch_sig:
/* Dispatch to the appropriate function. */ /* Dispatch to the appropriate function. */
sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler); sigproc_printf ("signal %d, signal handler %p", si.si_signo, handler);
rc = setup_handler (handler, thissig, tls); rc = setup_handler (handler, thissig, tls);
continue_now = false;
done: done:
if (continue_now)
{
(tls ?: _main_tls)->sig = SIGCONT;
SetEvent (tls->signal_arrived);
}
really_done:
sigproc_printf ("returning %d", rc); sigproc_printf ("returning %d", rc);
return rc; return rc;
@ -1293,11 +1311,11 @@ _cygtls::call_signal_handler ()
sigset_t this_oldmask = set_process_mask_delta (); sigset_t this_oldmask = set_process_mask_delta ();
int this_errno = saved_errno; int this_errno = saved_errno;
sig = 0; /* Flag that we can accept another signal */
reset_signal_arrived (); reset_signal_arrived ();
incyg = false;
sig = 0; /* Flag that we can accept another signal */
unlock (); /* unlock signal stack */ unlock (); /* unlock signal stack */
incyg = false;
/* no ucontext_t information provided yet, so third arg is NULL */ /* no ucontext_t information provided yet, so third arg is NULL */
thisfunc (thissig, &thissi, NULL); thisfunc (thissig, &thissi, NULL);
incyg = true; incyg = true;

View File

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

View File

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