winpthreads: tests: add missing subtests for normal mutexes
The mutex tests are named using pattern {type}[-static]-{subtest}.
Add missing subtests for normal mutexes.
Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com>
Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am
index 4e0b9a1..785da97 100644
--- a/mingw-w64-libraries/winpthreads/tests/Makefile.am
+++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am
@@ -129,7 +129,10 @@
pthread_mutex/mutex-types \
pthread_mutex/normal-basic \
pthread_mutex/normal-lock-recursive \
+ pthread_mutex/normal-static \
+ pthread_mutex/normal-static-lock-recursive \
pthread_mutex/normal-timedlock \
+ pthread_mutex/normal-trylock \
pthread_mutex/normal-trylock-recursive \
pthread_mutex/normal-unlock \
pthread_mutex/recursive-basic \
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static-lock-recursive.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static-lock-recursive.c
new file mode 100644
index 0000000..70fce15
--- /dev/null
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static-lock-recursive.c
@@ -0,0 +1,97 @@
+/*
+ Copyright (c) 2026 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "test.h"
+
+/**
+ * Test Summary:
+ *
+ * Main thread M creates (statically initialized) mutex L with type
+ * `PTHREAD_MUTEX_NORMAL`.
+ *
+ * Thread A locks L.
+ *
+ * Thread A attempts to lock L again; this must result in a dead lock.
+ *
+ * Thread M unlocks and destroys L.
+ */
+
+static LONG IsThreadABlocked = FALSE;
+
+static void *ThreadA(void *arg)
+{
+ pthread_mutex_t *mutex = arg;
+
+ assert(pthread_mutex_lock(mutex) == 0);
+ /**
+ * Signal thread M that thread A locked L.
+ */
+ InterlockedExchange(&IsThreadABlocked, TRUE);
+ /**
+ * Attempt to recursively lock NORMAL mutex must result in a dead lock.
+ * Wait for main thread to unlock...
+ */
+ assert(pthread_mutex_lock(mutex) == 0);
+ /**
+ * Signal thread M that thread A was unblocked.
+ */
+ InterlockedExchange(&IsThreadABlocked, FALSE);
+ assert(pthread_mutex_unlock(mutex) == 0);
+
+ return arg;
+}
+
+int main(void)
+{
+ pthread_mutex_t mutex = PTHREAD_NORMAL_MUTEX_INITIALIZER;
+ pthread_t thread;
+ void *result;
+
+ assert(pthread_create(&thread, NULL, ThreadA, &mutex) == 0);
+ /**
+ * Wait until thread A locks L.
+ */
+ while (!IsThreadABlocked) {
+ YieldProcessor();
+ }
+ Sleep(10);
+ /**
+ * Thread A must be deadlocked.
+ */
+ assert(IsThreadABlocked);
+ /**
+ * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is
+ * not owned by the calling thread is undefined behavior.
+ *
+ * Our implementation for NORMAL mutexes does not check ownership at all,
+ * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds.
+ */
+ do {
+ assert(pthread_mutex_unlock(&mutex) == 0);
+ YieldProcessor();
+ } while (IsThreadABlocked);
+ assert(pthread_join (thread, &result) == 0);
+ assert(result == &mutex);
+ assert(pthread_mutex_destroy(&mutex) == 0);
+
+ return 0;
+}
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static.c
new file mode 100644
index 0000000..bc041df
--- /dev/null
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-static.c
@@ -0,0 +1,53 @@
+/*
+ Copyright (c) 2026 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "test.h"
+
+/**
+ * Test Summary:
+ *
+ * This test is equivalent to `normal-basic.c`, except it uses statically
+ * initialized `pthread_mutex_t` object.
+ */
+
+int main(void)
+{
+ pthread_mutex_t mutex = PTHREAD_NORMAL_MUTEX_INITIALIZER;
+
+ assert(pthread_mutex_lock(&mutex) == 0);
+ assert(pthread_mutex_trylock(&mutex) == EBUSY);
+ assert(pthread_mutex_destroy(&mutex) == EBUSY);
+ assert(pthread_mutex_unlock(&mutex) == 0);
+ /**
+ * POSIX states that calling `pthread_mutex_unlock` on NORMAL mutex that is
+ * not owned by the calling thread is undefined behavior.
+ *
+ * Our implementation for NORMAL mutexes does not check ownership at all,
+ * so call to `pthread_mutex_unlock` on a valid NORMAL mutex always succeeds.
+ */
+ assert(pthread_mutex_unlock(&mutex) == 0);
+ assert(pthread_mutex_destroy(&mutex) == 0);
+ assert(mutex == (pthread_mutex_t)0);
+ assert(pthread_mutex_lock(&mutex) == EINVAL);
+
+ return 0;
+}
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-trylock.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-trylock.c
new file mode 100644
index 0000000..49af2f6
--- /dev/null
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/normal-trylock.c
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2026 mingw-w64 project
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+*/
+
+#include "test.h"
+
+/**
+ * Test Summary:
+ *
+ * Main thread M creates mutex L with type `PTHREAD_MUTEX_NORMAL` and locks it.
+ *
+ * Thread A attempts to lock L; since M owns L, call to `pthread_mutex_trylock`
+ * must fail with EBUSY.
+ *
+ * Thread M unlocks and destroys L.
+ */
+
+static void *ThreadA(void *arg)
+{
+ pthread_mutex_t *mutex = arg;
+ assert(pthread_mutex_trylock(mutex) == EBUSY);
+ return arg;
+}
+
+int main(void)
+{
+ pthread_mutex_t mutex = PTHREAD_NORMAL_MUTEX_INITIALIZER;
+ pthread_t thread;
+ void *result;
+
+ assert(pthread_mutex_lock(&mutex) == 0);
+ assert(pthread_create(&thread, NULL, ThreadA, &mutex) == 0);
+ assert(pthread_join(thread, &result) == 0);
+ assert(result == &mutex);
+ assert(pthread_mutex_unlock(&mutex) == 0);
+ assert(pthread_mutex_destroy(&mutex) == 0);
+
+ return 0;
+}