summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog5
-rw-r--r--winsup/cygwin/exceptions.cc34
2 files changed, 29 insertions, 10 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 60b05ddc9..56ca1027e 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,10 @@
2013-06-07 Christopher Faylor <me.cygwin2013@cgf.cx>
+ * exceptions.cc (_cygtls::handle_SIGCONT): Reinstate previous behavior
+ but make sure that yield() isn't called when signal stack is locked.
+
+2013-06-07 Christopher Faylor <me.cygwin2013@cgf.cx>
+
* exceptions.cc (exception::handle): Add comment explaining si_addr
behavior.
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index c1b313910..2fd75c65a 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1256,16 +1256,30 @@ _cygtls::handle_SIGCONT ()
{
myself->stopsig = 0;
myself->process_state &= ~PID_STOPPED;
- /* Carefully tell sig_handle_tty_stop to wake up. */
- lock ();
- sig = SIGCONT;
- SetEvent (signal_arrived);
- /* Make sure yield doesn't run under lock condition to avoid
- starvation of sig_handle_tty_stop. */
- unlock ();
- /* Wait until sig_handle_tty_stop woke up. */
- while (sig)
- yield ();
+ int state = 0;
+ /* Carefully tell sig_handle_tty_stop to wake up.
+ Make sure that any pending signal is handled before trying to
+ send a new one. Then make sure that SIGCONT has been recognized
+ before exiting the loop. */
+ while (state < 2)
+ {
+ lock ();
+ bool do_yield = !!sig;
+ if (do_yield)
+ /* signal still being processed */;
+ else if (state)
+ state++; /* state == 2: signal no longer being processed */
+ else
+ {
+ sig = SIGCONT;
+ SetEvent (signal_arrived);
+ state++; /* state == 1: alert sig_handle_tty_stop */
+ do_yield = true; /* wake up other thread */
+ }
+ unlock ();
+ if (do_yield)
+ yield ();
+ }
/* Tell wait_sig to handle any queued signals now that we're alive
again. */
sig_dispatch_pending (false);