aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Yano <takashi.yano@nifty.ne.jp>2025-02-28 16:52:59 +0900
committerTakashi Yano <takashi.yano@nifty.ne.jp>2025-03-04 04:26:36 +0900
commitf5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c (patch)
tree241ad7d6467d0e0dc04a208b91ea9de4ef59f98f
parent53483eddbce70247a28a9d41dd33e2c559925ed4 (diff)
downloadnewlib-f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c.zip
newlib-f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c.tar.gz
newlib-f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c.tar.bz2
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.Franke@t-online.de> Reviewed-by: Corinna Vinschen <corinna@vinschen.de> Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
-rw-r--r--winsup/cygwin/exceptions.cc25
1 files changed, 15 insertions, 10 deletions
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index f576c5f..c6e82b6 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)