]> Savannah Git Hosting - gnulib.git/commitdiff
windows-mutex, windows-timedmutex: Follow pthread_mutex_trylock spec.
authorBruno Haible <bruno@clisp.org>
Tue, 6 Aug 2024 13:14:25 +0000 (15:14 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 6 Aug 2024 13:14:25 +0000 (15:14 +0200)
* lib/windows-mutex.h (glwthread_mutex_t): Add 'owner' field.
* lib/windows-mutex.c: Include <stdlib.h>.
(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
lib/windows-mutex.c
lib/windows-mutex.h
lib/windows-timedmutex.c
lib/windows-timedmutex.h

index dc27670bda807c03aaa8fa1e05d51e297e3f5012..d7e5c44ddc9fca444a89c7ef7a1a501c55a9980a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2024-08-06  Bruno Haible  <bruno@clisp.org>
+
+       windows-mutex, windows-timedmutex: Follow pthread_mutex_trylock spec.
+       * lib/windows-mutex.h (glwthread_mutex_t): Add 'owner' field.
+       * lib/windows-mutex.c: Include <stdlib.h>.
+       (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  <bruno@clisp.org>
 
        Improve a comment.
index b112e13b6b9ec913afcf53b5f556735e907cd180..d258dbc1a9e1d0501a785a270c4741295287b575 100644 (file)
@@ -23,6 +23,7 @@
 #include "windows-mutex.h"
 
 #include <errno.h>
+#include <stdlib.h>
 
 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;
 }
index 88de4bdcadd00a4be076769e449ba6266cd10e5c..cb676c1b90454d80d8254452c41a14798d4a8ec4 100644 (file)
@@ -28,6 +28,7 @@
 typedef struct
         {
           glwthread_initguard_t guard; /* protects the initialization */
+          DWORD owner;
           CRITICAL_SECTION lock;
         }
         glwthread_mutex_t;
index 3dfff56dbe8fc31c56433c72de07984506046199..1beb56df625d49cce309dd1676886902cab56c88 100644 (file)
@@ -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
index e21879e1a1b273a0b96615f3a95d5a4202a42973..6ede4b2408cf5dd45dfac6b5693d0f7cd0103036 100644 (file)
@@ -30,6 +30,7 @@
 typedef struct
         {
           glwthread_initguard_t guard; /* protects the initialization */
+          DWORD owner;
           HANDLE event;
           CRITICAL_SECTION lock;
         }