[newlib-cygwin/cygwin-3_6-branch] Cygwin: thread: Allow fast_mutex to be acquired multiple times.

Takashi Yano tyan0@sourceware.org
Tue Apr 8 14:31:22 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=7930b49a502d6e6a3bd1edfcd42cdaca49cd0b4c

commit 7930b49a502d6e6a3bd1edfcd42cdaca49cd0b4c
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date:   Mon Mar 24 13:25:35 2025 +0900

    Cygwin: thread: Allow fast_mutex to be acquired multiple times.
    
    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_Str@hotmail.com>
    Reviewed-by: Corinna Vinschen <corinna@vinschen.de>
    Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>

Diff:
---
 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;
 };


More information about the Cygwin-cvs mailing list