winpthreads: mutex.c: improve `pthread_mutex_destroy`

Check whether mutex passed to `pthread_mutex_destroy` is owned by any thread,
including the calling thread, and fail with EBUSY in such case.

Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com>
Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-libraries/winpthreads/src/mutex.c b/mingw-w64-libraries/winpthreads/src/mutex.c
index 6db9d5a..5d1e15e 100644
--- a/mingw-w64-libraries/winpthreads/src/mutex.c
+++ b/mingw-w64-libraries/winpthreads/src/mutex.c
@@ -415,14 +415,54 @@
 
 int pthread_mutex_destroy(pthread_mutex_t *m)
 {
-  mutex_impl_t *mi = (mutex_impl_t *)*m;
-  if (!STATIC_MUTEX_INITIALIZER(mi)) {
-    CloseHandle(mi->event);
-    free(mi);
-    /* Sabotage attempts to re-use the mutex before initialising it again. */
-    *m = (pthread_mutex_t)NULL;
+  /**
+   * POSIX:
+   *
+   * If an implementation detects that the value specified by the mutex argument
+   * to pthread_mutex_destroy() does not refer to an initialized mutex, it is
+   * recommended that the function should fail and report an [EINVAL] error.
+   */
+  if (unlikely (m == NULL)) {
+    return EINVAL;
   }
 
+  mutex_impl_t *mi = (mutex_impl_t *)*m;
+
+  if (unlikely (mi == NULL)) {
+    return EINVAL;
+  }
+
+  /**
+   * If `m` points to a static initializer, attempt to immediately invalidate
+   * it in order to reduce window for other functions to attempt using it.
+   */
+  if (unlikely (STATIC_MUTEX_INITIALIZER (mi))) {
+    mutex_impl_t *mutex = InterlockedCompareExchangePointer ((void **)m, NULL, mi);
+
+    if (likely (mutex == mi) || unlikely (mutex == NULL)) {
+      return 0;
+    }
+
+    mi = mutex;
+  }
+
+  /**
+   * POSIX:
+   *
+   * If an implementation detects that the value specified by the mutex
+   * argument to pthread_mutex_destroy() refers to a locked mutex or a mutex
+   * that is referenced, it is recommended that the function should fail and
+   * report an [EBUSY] error.
+   */
+  if (InterlockedCompareExchange ((LONG *)&mi->state, Locked, Unlocked) != Unlocked) {
+    return EBUSY;
+  }
+
+  InterlockedExchangePointer ((void **)m, NULL);
+
+  CloseHandle (mi->event);
+  free (mi);
+
   return 0;
 }