diff options
author | Takashi Yano <takashi.yano@nifty.ne.jp> | 2025-02-28 16:52:59 +0900 |
---|---|---|
committer | Takashi Yano <takashi.yano@nifty.ne.jp> | 2025-03-04 04:26:36 +0900 |
commit | f5320f5a2aa0d87e4d3eea703b7ac102c2a6cf1c (patch) | |
tree | 241ad7d6467d0e0dc04a208b91ea9de4ef59f98f | |
parent | 53483eddbce70247a28a9d41dd33e2c559925ed4 (diff) | |
download | newlib-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.cc | 25 |
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) |