]> 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>
Mon, 12 Aug 2024 16:19:03 +0000 (18:19 +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 ed90d1229d058afda7ae20f61be68ea844106b64..9d917c6de3b71d409ee3c0989126324c7a143ead 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>
 
        gnulib-tool.py: Fix testdirs created with --without-tests.
index b112e13b6b9ec913afcf53b5f556735e907cd180..2ac73a0728a906ee9b24d98cb8a7a597dce0e48a 100644 (file)
 #include "windows-mutex.h"
 
 #include <errno.h>
+#include <stdlib.h>
 
 void
 glwthread_mutex_init (glwthread_mutex_t *mutex)
 {
+  mutex->owner = 0;
   InitializeCriticalSection (&mutex->lock);
   mutex->guard.done = 1;
 }
@@ -49,7 +51,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 +80,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 +103,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..3833cab129f9d2ab70e9a7a2803f640bfb929c44 100644 (file)
@@ -40,6 +40,7 @@ glwthread_timedmutex_init (glwthread_timedmutex_t *mutex)
   if (event == INVALID_HANDLE_VALUE)
     return EAGAIN;
   mutex->event = event;
+  mutex->owner = 0;
   InitializeCriticalSection (&mutex->lock);
   mutex->guard.done = 1;
   return 0;
@@ -72,7 +73,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 +111,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 +219,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 +242,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;
         }