Skip to content

Commit

Permalink
Cygwin: signal: Fix another deadlock between main and sig thread
Browse files Browse the repository at this point in the history
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: 26158dc("* 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]>
  • Loading branch information
tyan0 committed Nov 28, 2024
1 parent 57ce5f1 commit 9ae51bc
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 4 deletions.
10 changes: 7 additions & 3 deletions winsup/cygwin/exceptions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down
4 changes: 3 additions & 1 deletion winsup/cygwin/local_includes/cygtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -262,7 +264,7 @@ class _cygtls
{
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 *);
Expand Down

0 comments on commit 9ae51bc

Please sign in to comment.