Previously, the fast_mutex defined in thread.h could not be aquired multiple times, i.e., the thread causes deadlock if it attempted to acquire a lock already acquired by the thread. For example, a deadlock occurs if another pthread_key_create() is called in the destructor specified in the previous pthread_key_create(). This is because the run_all_destructors() calls the desructor via keys.for_each() where both for_each() and pthread_key_create() (that calls List_insert()) attempt to acquire the lock. With this patch, the fast_mutex can be acquired multiple times by the same thread similar to the behaviour of a Windows mutex. In this implementation, the mutex is released only when the number of unlock() calls matches the number of lock() calls.
Addresses: https://cygwin.com/pipermail/cygwin/2025-March/257705.html Fixes: 1a821390d11d ("fix race condition in List_insert") Reported-by: Yuyi Wang <strawberry_...@hotmail.com> Reviewed-by: Signed-off-by: Takashi Yano <takashi.y...@nifty.ne.jp> --- winsup/cygwin/local_includes/thread.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/local_includes/thread.h b/winsup/cygwin/local_includes/thread.h index b3496281e..025bfa2fc 100644 --- a/winsup/cygwin/local_includes/thread.h +++ b/winsup/cygwin/local_includes/thread.h @@ -31,7 +31,7 @@ class fast_mutex { public: fast_mutex () : - lock_counter (0), win32_obj_id (0) + tid (0), counter_self (0), lock_counter (0), win32_obj_id (0) { } @@ -55,17 +55,29 @@ public: void lock () { - if (InterlockedIncrement (&lock_counter) != 1) + if (!locked () && InterlockedIncrement (&lock_counter) != 1) cygwait (win32_obj_id, cw_infinite, cw_sig | cw_sig_restart); + tid = GetCurrentThreadId (); + counter_self++; } void unlock () { + if (!locked () || --counter_self > 0) + return; + tid = 0; if (InterlockedDecrement (&lock_counter)) ::SetEvent (win32_obj_id); } + bool locked () + { + return tid == GetCurrentThreadId (); + } + private: + DWORD tid; + int counter_self; LONG lock_counter; HANDLE win32_obj_id; }; -- 2.45.1