4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-13 04:29:09 +08:00

Cygwin: signal: Avoid frequent TLS lock/unlock for SIGCONT processing

It seems that current _cygtls::handle_SIGCONT() code sometimes falls
into a deadlock due to frequent TLS lock/unlock operation in the
yield() loop. With this patch, the yield() in the wait loop is placed
outside the TLS lock to avoid frequent TLS lock/unlock.

Fixes: 9ae51bcc51a7 ("Cygwin: signal: Fix another deadlock between main and sig thread")
Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
This commit is contained in:
Takashi Yano 2025-01-18 19:03:23 +09:00
parent b838c8d21a
commit f3a9f181b1
2 changed files with 15 additions and 25 deletions

View File

@ -1419,7 +1419,7 @@ api_fatal_debug ()
/* Attempt to carefully handle SIGCONT when we are stopped. */ /* Attempt to carefully handle SIGCONT when we are stopped. */
void void
_cygtls::handle_SIGCONT (threadlist_t * &tl_entry) _cygtls::handle_SIGCONT ()
{ {
if (NOTSTATE (myself, PID_STOPPED)) if (NOTSTATE (myself, PID_STOPPED))
return; return;
@ -1430,23 +1430,17 @@ _cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
Make sure that any pending signal is handled before trying to Make sure that any pending signal is handled before trying to
send a new one. Then make sure that SIGCONT has been recognized send a new one. Then make sure that SIGCONT has been recognized
before exiting the loop. */ before exiting the loop. */
bool sigsent = false; while (sig) /* Assume that it's ok to just test sig outside of a */
while (1) yield (); /* lock since setup_handler does it this way. */
if (sig) /* Assume that it's ok to just test sig outside of a
lock since setup_handler does it this way. */ lock ();
{ sig = SIGCONT;
cygheap->unlock_tls (tl_entry); set_signal_arrived (); /* alert sig_handle_tty_stop */
yield (); /* Attempt to schedule another thread. */ unlock ();
tl_entry = cygheap->find_tls (_main_tls);
} while (sig == SIGCONT)
else if (sigsent) yield ();
break; /* SIGCONT has been recognized by other thread */
else
{
sig = SIGCONT;
set_signal_arrived (); /* alert sig_handle_tty_stop */
sigsent = true;
}
/* Clear pending stop signals */ /* Clear pending stop signals */
sig_clear (SIGSTOP, false); sig_clear (SIGSTOP, false);
sig_clear (SIGTSTP, false); sig_clear (SIGTSTP, false);
@ -1478,11 +1472,7 @@ sigpacket::process ()
myself->rusage_self.ru_nsignals++; myself->rusage_self.ru_nsignals++;
if (si.si_signo == SIGCONT) if (si.si_signo == SIGCONT)
{ _main_tls->handle_SIGCONT ();
tl_entry = cygheap->find_tls (_main_tls);
_main_tls->handle_SIGCONT (tl_entry);
cygheap->unlock_tls (tl_entry);
}
/* SIGKILL is special. It always goes through. */ /* SIGKILL is special. It always goes through. */
if (si.si_signo == SIGKILL) if (si.si_signo == SIGKILL)

View File

@ -195,7 +195,7 @@ public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */
class cygthread *_ctinfo; class cygthread *_ctinfo;
class san *andreas; class san *andreas;
waitq wq; waitq wq;
int sig; volatile int sig;
unsigned incyg; unsigned incyg;
volatile unsigned spinning; volatile unsigned spinning;
volatile unsigned stacklock; volatile unsigned stacklock;
@ -276,7 +276,7 @@ public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */
{ {
will_wait_for_signal = false; will_wait_for_signal = false;
} }
void handle_SIGCONT (threadlist_t * &); void handle_SIGCONT ();
static void cleanup_early(struct _reent *); static void cleanup_early(struct _reent *);
private: private:
void call2 (DWORD (*) (void *, void *), void *, void *); void call2 (DWORD (*) (void *, void *), void *, void *);