4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-08 18:19:08 +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. */
void
_cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
_cygtls::handle_SIGCONT ()
{
if (NOTSTATE (myself, PID_STOPPED))
return;
@ -1430,23 +1430,17 @@ _cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
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. */
bool sigsent = false;
while (1)
if (sig) /* Assume that it's ok to just test sig outside of a
lock since setup_handler does it this way. */
{
cygheap->unlock_tls (tl_entry);
yield (); /* Attempt to schedule another thread. */
tl_entry = cygheap->find_tls (_main_tls);
}
else if (sigsent)
break; /* SIGCONT has been recognized by other thread */
else
{
while (sig) /* Assume that it's ok to just test sig outside of a */
yield (); /* lock since setup_handler does it this way. */
lock ();
sig = SIGCONT;
set_signal_arrived (); /* alert sig_handle_tty_stop */
sigsent = true;
}
unlock ();
while (sig == SIGCONT)
yield ();
/* Clear pending stop signals */
sig_clear (SIGSTOP, false);
sig_clear (SIGTSTP, false);
@ -1478,11 +1472,7 @@ sigpacket::process ()
myself->rusage_self.ru_nsignals++;
if (si.si_signo == SIGCONT)
{
tl_entry = cygheap->find_tls (_main_tls);
_main_tls->handle_SIGCONT (tl_entry);
cygheap->unlock_tls (tl_entry);
}
_main_tls->handle_SIGCONT ();
/* SIGKILL is special. It always goes through. */
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 san *andreas;
waitq wq;
int sig;
volatile int sig;
unsigned incyg;
volatile unsigned spinning;
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;
}
void handle_SIGCONT (threadlist_t * &);
void handle_SIGCONT ();
static void cleanup_early(struct _reent *);
private:
void call2 (DWORD (*) (void *, void *), void *, void *);