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

Takashi Yano via Cygwin-cvs <[email protected]>
Newsgroups gmane.os.cygwin.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=7930b49a502d6e6a3bd1edfcd42cdaca49cd0b4c

commit 7930b49a502d6e6a3bd1edfcd42cdaca49cd0b4c
Author: Takashi Yano <[email protected]>
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 <[email protected]>
    Reviewed-by: Corinna Vinschen <[email protected]>
    Signed-off-by: Takashi Yano <[email protected]>

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;
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.