From 0cd5825421831dc132e335a5b5cd7648bb2e334e Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 6 Aug 2024 15:14:25 +0200 Subject: [PATCH] windows-mutex, windows-timedmutex: Follow pthread_mutex_trylock spec. * lib/windows-mutex.h (glwthread_mutex_t): Add 'owner' field. * lib/windows-mutex.c: Include . (glwthread_mutex_lock): Set the 'owner' field after entering the critical section. (glwthread_mutex_trylock): Detect whether the lock was previously locked by this thread. Set the 'owner' field after entering the critical section. (glwthread_mutex_unlock): Clear the 'owner' field before leaving the critical section. * lib/windows-timedmutex.h (glwthread_timedmutex_t): Add 'owner' field. * lib/windows-timedmutex.c: (glwthread_timedmutex_lock): Set the 'owner' field after entering the critical section. (glwthread_timedmutex_trylock): Detect whether the lock was previously locked by this thread. Set the 'owner' field after entering the critical section. (glwthread_timedmutex_unlock): Clear the 'owner' field before leaving the critical section. --- ChangeLog | 21 +++++++++++++++++++++ lib/windows-mutex.c | 23 +++++++++++++++++++++++ lib/windows-mutex.h | 1 + lib/windows-timedmutex.c | 37 +++++++++++++++++++++++++++++++++++++ lib/windows-timedmutex.h | 1 + 5 files changed, 83 insertions(+) diff --git a/ChangeLog b/ChangeLog index dc27670bda..d7e5c44ddc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2024-08-06 Bruno Haible + + windows-mutex, windows-timedmutex: Follow pthread_mutex_trylock spec. + * lib/windows-mutex.h (glwthread_mutex_t): Add 'owner' field. + * lib/windows-mutex.c: Include . + (glwthread_mutex_lock): Set the 'owner' field after entering the + critical section. + (glwthread_mutex_trylock): Detect whether the lock was previously locked + by this thread. Set the 'owner' field after entering the critical + section. + (glwthread_mutex_unlock): Clear the 'owner' field before leaving the + critical section. + * lib/windows-timedmutex.h (glwthread_timedmutex_t): Add 'owner' field. + * lib/windows-timedmutex.c: (glwthread_timedmutex_lock): Set the 'owner' + field after entering the critical section. + (glwthread_timedmutex_trylock): Detect whether the lock was previously + locked by this thread. Set the 'owner' field after entering the critical + section. + (glwthread_timedmutex_unlock): Clear the 'owner' field before leaving + the critical section. + 2024-08-05 Bruno Haible Improve a comment. diff --git a/lib/windows-mutex.c b/lib/windows-mutex.c index b112e13b6b..d258dbc1a9 100644 --- a/lib/windows-mutex.c +++ b/lib/windows-mutex.c @@ -23,6 +23,7 @@ #include "windows-mutex.h" #include +#include void glwthread_mutex_init (glwthread_mutex_t *mutex) @@ -49,7 +50,13 @@ glwthread_mutex_lock (glwthread_mutex_t *mutex) Sleep (0); } } + /* If this thread already owns the mutex, POSIX pthread_mutex_lock() is + required to deadlock here. But let's not do that on purpose. */ EnterCriticalSection (&mutex->lock); + { + DWORD self = GetCurrentThreadId (); + mutex->owner = self; + } return 0; } @@ -72,6 +79,21 @@ glwthread_mutex_trylock (glwthread_mutex_t *mutex) } if (!TryEnterCriticalSection (&mutex->lock)) return EBUSY; + { + DWORD self = GetCurrentThreadId (); + /* TryEnterCriticalSection succeeded. This means that the mutex was either + previously unlocked (and thus mutex->owner == 0) or previously locked by + this thread (and thus mutex->owner == self). Since the mutex is meant to + be plain, we need to fail in the latter case. */ + if (mutex->owner == self) + { + LeaveCriticalSection (&mutex->lock); + return EBUSY; + } + if (mutex->owner != 0) + abort (); + mutex->owner = self; + } return 0; } @@ -80,6 +102,7 @@ glwthread_mutex_unlock (glwthread_mutex_t *mutex) { if (!mutex->guard.done) return EINVAL; + mutex->owner = 0; LeaveCriticalSection (&mutex->lock); return 0; } diff --git a/lib/windows-mutex.h b/lib/windows-mutex.h index 88de4bdcad..cb676c1b90 100644 --- a/lib/windows-mutex.h +++ b/lib/windows-mutex.h @@ -28,6 +28,7 @@ typedef struct { glwthread_initguard_t guard; /* protects the initialization */ + DWORD owner; CRITICAL_SECTION lock; } glwthread_mutex_t; diff --git a/lib/windows-timedmutex.c b/lib/windows-timedmutex.c index 3dfff56dbe..1beb56df62 100644 --- a/lib/windows-timedmutex.c +++ b/lib/windows-timedmutex.c @@ -72,7 +72,13 @@ glwthread_timedmutex_lock (glwthread_timedmutex_t *mutex) Sleep (0); } } + /* If this thread already owns the mutex, POSIX pthread_mutex_lock() is + required to deadlock here. But let's not do that on purpose. */ EnterCriticalSection (&mutex->lock); + { + DWORD self = GetCurrentThreadId (); + mutex->owner = self; + } return 0; } @@ -104,6 +110,21 @@ glwthread_timedmutex_trylock (glwthread_timedmutex_t *mutex) } if (!TryEnterCriticalSection (&mutex->lock)) return EBUSY; + { + DWORD self = GetCurrentThreadId (); + /* TryEnterCriticalSection succeeded. This means that the mutex was either + previously unlocked (and thus mutex->owner == 0) or previously locked by + this thread (and thus mutex->owner == self). Since the mutex is meant to + be plain, we need to fail in the latter case. */ + if (mutex->owner == self) + { + LeaveCriticalSection (&mutex->lock); + return EBUSY; + } + if (mutex->owner != 0) + abort (); + mutex->owner = self; + } return 0; } @@ -197,6 +218,21 @@ glwthread_timedmutex_timedlock (glwthread_timedmutex_t *mutex, locking it now. */ } } + { + DWORD self = GetCurrentThreadId (); + /* TryEnterCriticalSection succeeded. This means that the mutex was either + previously unlocked (and thus mutex->owner == 0) or previously locked by + this thread (and thus mutex->owner == self). Since the mutex is meant to + be plain, it is useful to fail in the latter case. */ + if (mutex->owner == self) + { + LeaveCriticalSection (&mutex->lock); + return EDEADLK; + } + if (mutex->owner != 0) + abort (); + mutex->owner = self; + } return 0; } @@ -205,6 +241,7 @@ glwthread_timedmutex_unlock (glwthread_timedmutex_t *mutex) { if (!mutex->guard.done) return EINVAL; + mutex->owner = 0; LeaveCriticalSection (&mutex->lock); /* Notify one of the threads that were waiting with a timeout. */ /* SetEvent diff --git a/lib/windows-timedmutex.h b/lib/windows-timedmutex.h index e21879e1a1..6ede4b2408 100644 --- a/lib/windows-timedmutex.h +++ b/lib/windows-timedmutex.h @@ -30,6 +30,7 @@ typedef struct { glwthread_initguard_t guard; /* protects the initialization */ + DWORD owner; HANDLE event; CRITICAL_SECTION lock; } -- 2.39.5