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;
+}