[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