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:
parent
b838c8d21a
commit
f3a9f181b1
@ -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 ();
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
sig = SIGCONT;
|
sig = SIGCONT;
|
||||||
set_signal_arrived (); /* alert sig_handle_tty_stop */
|
set_signal_arrived (); /* alert sig_handle_tty_stop */
|
||||||
sigsent = true;
|
unlock ();
|
||||||
}
|
|
||||||
|
while (sig == SIGCONT)
|
||||||
|
yield ();
|
||||||
|
|
||||||
/* 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)
|
||||||
|
@ -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 *);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user