* 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-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.
#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;
}
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;
}
}
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;
}
{
if (!mutex->guard.done)
return EINVAL;
+ mutex->owner = 0;
LeaveCriticalSection (&mutex->lock);
return 0;
}
typedef struct
{
glwthread_initguard_t guard; /* protects the initialization */
+ DWORD owner;
CRITICAL_SECTION lock;
}
glwthread_mutex_t;
if (event == INVALID_HANDLE_VALUE)
return EAGAIN;
mutex->event = event;
+ mutex->owner = 0;
InitializeCriticalSection (&mutex->lock);
mutex->guard.done = 1;
return 0;
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;
}
}
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;
}
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;
}
{
if (!mutex->guard.done)
return EINVAL;
+ mutex->owner = 0;
LeaveCriticalSection (&mutex->lock);
/* Notify one of the threads that were waiting with a timeout. */
/* SetEvent
typedef struct
{
glwthread_initguard_t guard; /* protects the initialization */
+ DWORD owner;
HANDLE event;
CRITICAL_SECTION lock;
}