https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=f930a973bd98dfa2ade96e2ae2c4e39554a80f5f
commit f930a973bd98dfa2ade96e2ae2c4e39554a80f5f Author: Takashi Yano <[email protected]> AuthorDate: Wed Nov 27 20:03:55 2024 +0900 Commit: Corinna Vinschen <[email protected]> CommitDate: Fri Dec 6 11:30:24 2024 +0100 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 <[email protected]> Reviewed-by: Corinna Vinschen <[email protected]> Signed-off-by: Takashi Yano <[email protected]> (cherry picked from commit 9ae51bcc51a7901559c476e6301597760c2726fd) Diff: --- 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 60c1f594f8d4..42556093adf5 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1419,7 +1419,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; @@ -1434,7 +1434,11 @@ _cygtls::handle_SIGCONT () while (1) if (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 @@ -1476,7 +1480,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 f67e9136c326..f967bb9cc272 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. */ @@ -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 *);
