Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2013-04-09 05:01:19 +0400
committerChristopher Faylor <me@cgf.cx>2013-04-09 05:01:19 +0400
commit9d2155089e8709977ef012cfdfd88d511b92d154 (patch)
treeb2d6845c34da33952996e16a1e637f61268ae351
parent037ad80a525e5be3088bcb3b34546498695e746f (diff)
* 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.
-rw-r--r--winsup/cygwin/ChangeLog35
-rw-r--r--winsup/cygwin/cygtls.h8
-rw-r--r--winsup/cygwin/cygwait.cc10
-rw-r--r--winsup/cygwin/cygwait.h5
-rw-r--r--winsup/cygwin/exceptions.cc102
-rw-r--r--winsup/cygwin/sigproc.cc135
-rw-r--r--winsup/cygwin/sigproc.h2
7 files changed, 156 insertions, 141 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index e83a81597..8fbe9a821 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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.
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index 5ddb9e199..5463ed85c 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -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*/
diff --git a/winsup/cygwin/cygwait.cc b/winsup/cygwin/cygwait.cc
index b0476660c..fcf31b39b 100644
--- a/winsup/cygwin/cygwait.cc
+++ b/winsup/cygwin/cygwait.cc
@@ -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;
diff --git a/winsup/cygwin/cygwait.h b/winsup/cygwin/cygwait.h
index 707976786..496817bcf 100644
--- a/winsup/cygwin/cygwait.h
+++ b/winsup/cygwin/cygwait.h
@@ -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;
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;
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 4bf6f5630..e585877b9 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -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);
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index 9c70c2c2d..c4313f056 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -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),