In _cygtls::handle_SIGCONT(), the sig thread waits for the main thread processing the signal without unlocking tls area. This causes a deadlock if the main thread tries to acquire a lock for the tls area meanwhile. With this patch, unlock 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.fra...@t-online.de> Reviewed-by: Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp> --- winsup/cygwin/exceptions.cc | 10 +++++++--- winsup/cygwin/local_includes/cygtls.h | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 3b31e65c1..0f8c21939 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -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. */ - yield (); /* Attempt to schedule another thread. */ + { + 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); } diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index fb5b02b4c..ca9ef7dfb 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -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. */ @@ -269,7 +271,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 *); -- 2.45.1