pthread_mutex_trylock is required to fail with EBUSY if the mutex is a
non-recursive one and it is already locked by the current thread.
Similarly for mtx_trylock.
On native Windows, I observe that the Gnulib implementation does not
follow this spec, because
- It uses the windows-mutex and windows-timedmutex modules.
- This code uses the TryEnterCriticalSection function.
- This function succeeds if the current thread already holds the lock,
because a Windows CRITICAL_SECTION is semantically a recursive lock.
These patches fixes it, and add unit tests to verify the behaviour.
2024-08-06 Bruno Haible <[email protected]>
windows-timedrecmutex: Add tests.
* tests/test-windows-timedrecmutex-type.c: New file.
* modules/windows-timedrecmutex-tests: New file.
windows-recmutex: Add tests.
* tests/test-windows-recmutex-type.c: New file.
* modules/windows-recmutex-tests: New file.
windows-timedmutex: Add tests.
* tests/test-windows-timedmutex-type.c: New file.
* modules/windows-timedmutex-tests: New file.
windows-mutex: Add tests.
* tests/test-windows-mutex-type.c: New file.
* modules/windows-mutex-tests: New file.
2024-08-06 Bruno Haible <[email protected]>
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.
>From 0cd5825421831dc132e335a5b5cd7648bb2e334e Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 6 Aug 2024 15:14:25 +0200
Subject: [PATCH 1/5] 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.
---
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 <[email protected]>
+
+ 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 <[email protected]>
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 <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;
}
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.34.1
>From 735ca8884afd4755c4733a6c590006b257474b66 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 6 Aug 2024 15:17:03 +0200
Subject: [PATCH 2/5] windows-mutex: Add tests.
* tests/test-windows-mutex-type.c: New file.
* modules/windows-mutex-tests: New file.
---
ChangeLog | 6 +++
modules/windows-mutex-tests | 11 +++++
tests/test-windows-mutex-type.c | 78 +++++++++++++++++++++++++++++++++
3 files changed, 95 insertions(+)
create mode 100644 modules/windows-mutex-tests
create mode 100644 tests/test-windows-mutex-type.c
diff --git a/ChangeLog b/ChangeLog
index d7e5c44ddc..31c40e03ab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2024-08-06 Bruno Haible <[email protected]>
+
+ windows-mutex: Add tests.
+ * tests/test-windows-mutex-type.c: New file.
+ * modules/windows-mutex-tests: New file.
+
2024-08-06 Bruno Haible <[email protected]>
windows-mutex, windows-timedmutex: Follow pthread_mutex_trylock spec.
diff --git a/modules/windows-mutex-tests b/modules/windows-mutex-tests
new file mode 100644
index 0000000000..9563664aef
--- /dev/null
+++ b/modules/windows-mutex-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-windows-mutex-type.c
+tests/macros.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-windows-mutex-type
+check_PROGRAMS += test-windows-mutex-type
diff --git a/tests/test-windows-mutex-type.c b/tests/test-windows-mutex-type.c
new file mode 100644
index 0000000000..54d1589588
--- /dev/null
+++ b/tests/test-windows-mutex-type.c
@@ -0,0 +1,78 @@
+/* Test of locking in multithreaded situations.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <[email protected]>, 2024. */
+
+#include <config.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+/* Specification. */
+# include "windows-mutex.h"
+
+# include <errno.h>
+# include <stdio.h>
+# include <string.h>
+
+# include "macros.h"
+
+/* Returns the effective type of a lock. */
+static const char *
+get_effective_type (glwthread_mutex_t *lock)
+{
+ /* Lock once. */
+ ASSERT (glwthread_mutex_lock (lock) == 0);
+
+ /* Try to lock a second time. */
+ int err = glwthread_mutex_trylock (lock);
+ if (err == 0)
+ return "RECURSIVE";
+ if (err == EBUSY)
+ return "NORMAL";
+
+ return "impossible!";
+}
+
+int
+main ()
+{
+ /* Find the effective type of a lock. */
+ const char *type;
+ {
+ glwthread_mutex_t lock;
+ glwthread_mutex_init (&lock);
+ type = get_effective_type (&lock);
+ }
+
+ printf ("type = %s\n", type);
+
+ ASSERT (strcmp (type, "NORMAL") == 0);
+
+ return test_exit_status;
+}
+
+#else
+
+# include <stdio.h>
+
+int
+main ()
+{
+ fputs ("Skipping test: not a native Windows system\n", stderr);
+ return 77;
+}
+
+#endif
--
2.34.1
>From d46563a004044dd898c4277eb3d99275017bbe82 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 6 Aug 2024 15:18:18 +0200
Subject: [PATCH 3/5] windows-timedmutex: Add tests.
* tests/test-windows-timedmutex-type.c: New file.
* modules/windows-timedmutex-tests: New file.
---
ChangeLog | 4 ++
modules/windows-timedmutex-tests | 11 ++++
tests/test-windows-timedmutex-type.c | 78 ++++++++++++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 100644 modules/windows-timedmutex-tests
create mode 100644 tests/test-windows-timedmutex-type.c
diff --git a/ChangeLog b/ChangeLog
index 31c40e03ab..244c8e3b06 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2024-08-06 Bruno Haible <[email protected]>
+ windows-timedmutex: Add tests.
+ * tests/test-windows-timedmutex-type.c: New file.
+ * modules/windows-timedmutex-tests: New file.
+
windows-mutex: Add tests.
* tests/test-windows-mutex-type.c: New file.
* modules/windows-mutex-tests: New file.
diff --git a/modules/windows-timedmutex-tests b/modules/windows-timedmutex-tests
new file mode 100644
index 0000000000..9a22bb8d97
--- /dev/null
+++ b/modules/windows-timedmutex-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-windows-timedmutex-type.c
+tests/macros.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-windows-timedmutex-type
+check_PROGRAMS += test-windows-timedmutex-type
diff --git a/tests/test-windows-timedmutex-type.c b/tests/test-windows-timedmutex-type.c
new file mode 100644
index 0000000000..9c63ccd46c
--- /dev/null
+++ b/tests/test-windows-timedmutex-type.c
@@ -0,0 +1,78 @@
+/* Test of locking in multithreaded situations.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <[email protected]>, 2024. */
+
+#include <config.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+/* Specification. */
+# include "windows-timedmutex.h"
+
+# include <errno.h>
+# include <stdio.h>
+# include <string.h>
+
+# include "macros.h"
+
+/* Returns the effective type of a lock. */
+static const char *
+get_effective_type (glwthread_timedmutex_t *lock)
+{
+ /* Lock once. */
+ ASSERT (glwthread_timedmutex_lock (lock) == 0);
+
+ /* Try to lock a second time. */
+ int err = glwthread_timedmutex_trylock (lock);
+ if (err == 0)
+ return "RECURSIVE";
+ if (err == EBUSY)
+ return "NORMAL";
+
+ return "impossible!";
+}
+
+int
+main ()
+{
+ /* Find the effective type of a lock. */
+ const char *type;
+ {
+ glwthread_timedmutex_t lock;
+ ASSERT (glwthread_timedmutex_init (&lock) == 0);
+ type = get_effective_type (&lock);
+ }
+
+ printf ("type = %s\n", type);
+
+ ASSERT (strcmp (type, "NORMAL") == 0);
+
+ return test_exit_status;
+}
+
+#else
+
+# include <stdio.h>
+
+int
+main ()
+{
+ fputs ("Skipping test: not a native Windows system\n", stderr);
+ return 77;
+}
+
+#endif
--
2.34.1
>From 2f65f0931f39d8276118a1000278ee02691fc32d Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 6 Aug 2024 15:19:31 +0200
Subject: [PATCH 4/5] windows-recmutex: Add tests.
* tests/test-windows-recmutex-type.c: New file.
* modules/windows-recmutex-tests: New file.
---
ChangeLog | 4 ++
modules/windows-recmutex-tests | 11 +++++
tests/test-windows-recmutex-type.c | 78 ++++++++++++++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 100644 modules/windows-recmutex-tests
create mode 100644 tests/test-windows-recmutex-type.c
diff --git a/ChangeLog b/ChangeLog
index 244c8e3b06..5e6ab7af6a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2024-08-06 Bruno Haible <[email protected]>
+ windows-recmutex: Add tests.
+ * tests/test-windows-recmutex-type.c: New file.
+ * modules/windows-recmutex-tests: New file.
+
windows-timedmutex: Add tests.
* tests/test-windows-timedmutex-type.c: New file.
* modules/windows-timedmutex-tests: New file.
diff --git a/modules/windows-recmutex-tests b/modules/windows-recmutex-tests
new file mode 100644
index 0000000000..85da2ab9a5
--- /dev/null
+++ b/modules/windows-recmutex-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-windows-recmutex-type.c
+tests/macros.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-windows-recmutex-type
+check_PROGRAMS += test-windows-recmutex-type
diff --git a/tests/test-windows-recmutex-type.c b/tests/test-windows-recmutex-type.c
new file mode 100644
index 0000000000..72cc5d17ef
--- /dev/null
+++ b/tests/test-windows-recmutex-type.c
@@ -0,0 +1,78 @@
+/* Test of locking in multithreaded situations.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <[email protected]>, 2024. */
+
+#include <config.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+/* Specification. */
+# include "windows-recmutex.h"
+
+# include <errno.h>
+# include <stdio.h>
+# include <string.h>
+
+# include "macros.h"
+
+/* Returns the effective type of a lock. */
+static const char *
+get_effective_type (glwthread_recmutex_t *lock)
+{
+ /* Lock once. */
+ ASSERT (glwthread_recmutex_lock (lock) == 0);
+
+ /* Try to lock a second time. */
+ int err = glwthread_recmutex_trylock (lock);
+ if (err == 0)
+ return "RECURSIVE";
+ if (err == EBUSY)
+ return "NORMAL";
+
+ return "impossible!";
+}
+
+int
+main ()
+{
+ /* Find the effective type of a lock. */
+ const char *type;
+ {
+ glwthread_recmutex_t lock;
+ glwthread_recmutex_init (&lock);
+ type = get_effective_type (&lock);
+ }
+
+ printf ("type = %s\n", type);
+
+ ASSERT (strcmp (type, "RECURSIVE") == 0);
+
+ return test_exit_status;
+}
+
+#else
+
+# include <stdio.h>
+
+int
+main ()
+{
+ fputs ("Skipping test: not a native Windows system\n", stderr);
+ return 77;
+}
+
+#endif
--
2.34.1
>From 65162c3519d7d718e957d35e6a1cf42d1736db5e Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 6 Aug 2024 15:20:23 +0200
Subject: [PATCH 5/5] windows-timedrecmutex: Add tests.
* tests/test-windows-timedrecmutex-type.c: New file.
* modules/windows-timedrecmutex-tests: New file.
---
ChangeLog | 4 ++
modules/windows-timedrecmutex-tests | 11 ++++
tests/test-windows-timedrecmutex-type.c | 78 +++++++++++++++++++++++++
3 files changed, 93 insertions(+)
create mode 100644 modules/windows-timedrecmutex-tests
create mode 100644 tests/test-windows-timedrecmutex-type.c
diff --git a/ChangeLog b/ChangeLog
index 5e6ab7af6a..db84b220e2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2024-08-06 Bruno Haible <[email protected]>
+ windows-timedrecmutex: Add tests.
+ * tests/test-windows-timedrecmutex-type.c: New file.
+ * modules/windows-timedrecmutex-tests: New file.
+
windows-recmutex: Add tests.
* tests/test-windows-recmutex-type.c: New file.
* modules/windows-recmutex-tests: New file.
diff --git a/modules/windows-timedrecmutex-tests b/modules/windows-timedrecmutex-tests
new file mode 100644
index 0000000000..2e6c0cc55e
--- /dev/null
+++ b/modules/windows-timedrecmutex-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-windows-timedrecmutex-type.c
+tests/macros.h
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-windows-timedrecmutex-type
+check_PROGRAMS += test-windows-timedrecmutex-type
diff --git a/tests/test-windows-timedrecmutex-type.c b/tests/test-windows-timedrecmutex-type.c
new file mode 100644
index 0000000000..a61677cafa
--- /dev/null
+++ b/tests/test-windows-timedrecmutex-type.c
@@ -0,0 +1,78 @@
+/* Test of locking in multithreaded situations.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <[email protected]>, 2024. */
+
+#include <config.h>
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+/* Specification. */
+# include "windows-timedrecmutex.h"
+
+# include <errno.h>
+# include <stdio.h>
+# include <string.h>
+
+# include "macros.h"
+
+/* Returns the effective type of a lock. */
+static const char *
+get_effective_type (glwthread_timedrecmutex_t *lock)
+{
+ /* Lock once. */
+ ASSERT (glwthread_timedrecmutex_lock (lock) == 0);
+
+ /* Try to lock a second time. */
+ int err = glwthread_timedrecmutex_trylock (lock);
+ if (err == 0)
+ return "RECURSIVE";
+ if (err == EBUSY)
+ return "NORMAL";
+
+ return "impossible!";
+}
+
+int
+main ()
+{
+ /* Find the effective type of a lock. */
+ const char *type;
+ {
+ glwthread_timedrecmutex_t lock;
+ ASSERT (glwthread_timedrecmutex_init (&lock) == 0);
+ type = get_effective_type (&lock);
+ }
+
+ printf ("type = %s\n", type);
+
+ ASSERT (strcmp (type, "RECURSIVE") == 0);
+
+ return test_exit_status;
+}
+
+#else
+
+# include <stdio.h>
+
+int
+main ()
+{
+ fputs ("Skipping test: not a native Windows system\n", stderr);
+ return 77;
+}
+
+#endif
--
2.34.1