Cygwin: signal: Fix another deadlock between main and sig thread
In _cygtls::handle_SIGCONT(), the sig thread waits for the main thread to process the signal without unlocking the TLS area. This causes a deadlock if the main thread tries to acquire a lock for the TLS area in the meantime. With this patch, unlock the TLS before calling yield() in handle_SIGCONT(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 26158dc3e9c2("* exceptions.cc (sigpacket::process): Lock _cygtls area of thread before accessing it.") 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>
This commit is contained in:
parent
57ce5f1e0b
commit
9ae51bcc51
|
@ -1421,7 +1421,7 @@ api_fatal_debug ()
|
|||
|
||||
/* Attempt to carefully handle SIGCONT when we are stopped. */
|
||||
void
|
||||
_cygtls::handle_SIGCONT ()
|
||||
_cygtls::handle_SIGCONT (threadlist_t * &tl_entry)
|
||||
{
|
||||
if (NOTSTATE (myself, PID_STOPPED))
|
||||
return;
|
||||
|
@ -1436,7 +1436,11 @@ _cygtls::handle_SIGCONT ()
|
|||
while (1)
|
||||
if (current_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
|
||||
|
@ -1478,7 +1482,7 @@ sigpacket::process ()
|
|||
if (si.si_signo == SIGCONT)
|
||||
{
|
||||
tl_entry = cygheap->find_tls (_main_tls);
|
||||
_main_tls->handle_SIGCONT ();
|
||||
_main_tls->handle_SIGCONT (tl_entry);
|
||||
cygheap->unlock_tls (tl_entry);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,8 @@ extern "C" int __ljfault (jmp_buf, int);
|
|||
|
||||
typedef uintptr_t __tlsstack_t;
|
||||
|
||||
struct threadlist_t;
|
||||
|
||||
class _cygtls
|
||||
{
|
||||
public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */
|
||||
|
@ -262,7 +264,7 @@ public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */
|
|||
{
|
||||
will_wait_for_signal = false;
|
||||
}
|
||||
void handle_SIGCONT ();
|
||||
void handle_SIGCONT (threadlist_t * &);
|
||||
static void cleanup_early(struct _reent *);
|
||||
private:
|
||||
void call2 (DWORD (*) (void *, void *), void *, void *);
|
||||
|
|
Loading…
Reference in New Issue