https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c

commit f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c
Author: Takashi Yano <takashi.y...@nifty.ne.jp>
Date:   Fri Feb 28 16:52:59 2025 +0900

    Cygwin: signal: Fix deadlock on SIGCONT
    
    If SIGCONT starts processing while __SIGFLUSHFAST is ongoing,
    _main_tls->current_sig will never be cleared because the signal
    processing is stopped while waiting for the wake-up event in the
    main thread. This leads to a deadlock in the while loop waiting for
    current_sig to be cleared. With this patch, the function returns to
    wait_sig() if current_sig is set, rather than waiting for it in the
    while loop.
    
    Addresses: https://cygwin.com/pipermail/cygwin/2025-February/257473.html
    Fixes: 9d2155089e87 ("(sigpacket::process): Call handle_SIGCONT early to 
deal with SIGCONT.")
    Reported-by: Christian Franke <christian.fra...@t-online.de>
    Reviewed-by: Corinna Vinschen <cori...@vinschen.de>
    Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp>

Diff:
---
 winsup/cygwin/exceptions.cc | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index f576c5ff2..c6e82b6c5 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1425,23 +1425,18 @@ _cygtls::handle_SIGCONT ()
   if (NOTSTATE (myself, PID_STOPPED))
     return;
 
-  myself->stopsig = 0;
-  myself->process_state &= ~PID_STOPPED;
-  /* 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 (current_sig)  /* Assume that it's ok to just test sig outside of a */
-    yield ();          /* lock since setup_handler does it this way.  */
-
   lock ();
   current_sig = SIGCONT;
   set_signal_arrived (); /* alert sig_handle_tty_stop */
   unlock ();
 
+  /* Make sure that SIGCONT has been recognized before exiting the loop. */
   while (current_sig == SIGCONT)
     yield ();
 
+  myself->stopsig = 0;
+  myself->process_state &= ~PID_STOPPED;
+
   /* Clear pending stop signals */
   sig_clear (SIGSTOP, false);
   sig_clear (SIGTSTP, false);
@@ -1473,7 +1468,17 @@ sigpacket::process ()
   myself->rusage_self.ru_nsignals++;
 
   if (si.si_signo == SIGCONT)
-    _main_tls->handle_SIGCONT ();
+    {
+      /* Carefully tell sig_handle_tty_stop to wake up.
+        Make sure that any pending signal is handled before trying to
+        send a new one. */
+      if (_main_tls->current_sig)
+       {
+         rc = -1;
+         goto done;
+       }
+      _main_tls->handle_SIGCONT ();
+    }
 
   /* SIGKILL is special.  It always goes through.  */
   if (si.si_signo == SIGKILL)

Reply via email to