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:
parent
b838c8d21a
commit
f3a9f181b1
@ -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)
|
||||
|
@ -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 *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user