Skip to content

Commit 7930b49

Browse files
committed
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: 1a82139 ("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]>
1 parent dcb12dd commit 7930b49

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

winsup/cygwin/local_includes/thread.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class fast_mutex
3131
{
3232
public:
3333
fast_mutex () :
34-
lock_counter (0), win32_obj_id (0)
34+
tid (0), counter_self (0), lock_counter (0), win32_obj_id (0)
3535
{
3636
}
3737

@@ -55,17 +55,29 @@ class fast_mutex
5555

5656
void lock ()
5757
{
58-
if (InterlockedIncrement (&lock_counter) != 1)
58+
if (!locked () && InterlockedIncrement (&lock_counter) != 1)
5959
cygwait (win32_obj_id, cw_infinite, cw_sig | cw_sig_restart);
60+
tid = GetCurrentThreadId ();
61+
counter_self++;
6062
}
6163

6264
void unlock ()
6365
{
66+
if (!locked () || --counter_self > 0)
67+
return;
68+
tid = 0;
6469
if (InterlockedDecrement (&lock_counter))
6570
::SetEvent (win32_obj_id);
6671
}
6772

73+
bool locked ()
74+
{
75+
return tid == GetCurrentThreadId ();
76+
}
77+
6878
private:
79+
DWORD tid;
80+
int counter_self;
6981
LONG lock_counter;
7082
HANDLE win32_obj_id;
7183
};

0 commit comments

Comments
 (0)