From da6461a4d5e9df13e5f14b4b078914eac1b80735 Mon Sep 17 00:00:00 2001
From: Christopher Faylor <me@cgf.cx>
Date: Fri, 7 Jun 2013 17:09:56 +0000
Subject: [PATCH] * exceptions.cc (_cygtls::handle_SIGCONT): Reinstate previous
 behavior but make sure that yield() isn't called when signal stack is locked.

---
 winsup/cygwin/ChangeLog     |  5 +++++
 winsup/cygwin/exceptions.cc | 34 ++++++++++++++++++++++++----------
 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,3 +1,8 @@
+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
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);