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

Reply via email to