winpthreads: mutex.c: implement `pthread_mutexattr_{set,get}robust` functions

This change is a preparation step for implementing robust mutexes.

Add new test `pthread_mutex/attr-robust.c`.

Signed-off-by: Kirill Makurin <maiddaisuki@outlook.com>
Signed-off-by: LIU Hao <lh_mouse@126.com>
diff --git a/mingw-w64-libraries/winpthreads/include/pthread.h b/mingw-w64-libraries/winpthreads/include/pthread.h
index f415a06..a61753c 100644
--- a/mingw-w64-libraries/winpthreads/include/pthread.h
+++ b/mingw-w64-libraries/winpthreads/include/pthread.h
@@ -231,6 +231,9 @@
 #define PTHREAD_MUTEX_PRIVATE 0
 #define PTHREAD_MUTEX_SHARED  1
 
+#define PTHREAD_MUTEX_STALLED 0
+#define PTHREAD_MUTEX_ROBUST  1
+
 typedef unsigned pthread_mutexattr_t;
 
 WINPTHREAD_API int pthread_mutexattr_init(pthread_mutexattr_t *);
@@ -243,6 +246,8 @@
 WINPTHREAD_API int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *, int *);
 WINPTHREAD_API int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int);
 WINPTHREAD_API int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *);
+WINPTHREAD_API int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int);
+WINPTHREAD_API int pthread_mutexattr_getrobust(const pthread_mutexattr_t *, int *);
 
 typedef intptr_t pthread_mutex_t;
 
diff --git a/mingw-w64-libraries/winpthreads/src/mutex.c b/mingw-w64-libraries/winpthreads/src/mutex.c
index 555804c..152c561 100644
--- a/mingw-w64-libraries/winpthreads/src/mutex.c
+++ b/mingw-w64-libraries/winpthreads/src/mutex.c
@@ -79,8 +79,6 @@
  * - pthread_mutex_clocklock()
  * - pthread_mutex_getprioceiling()
  * - pthread_mutex_setprioceiling()
- * - pthread_mutexattr_getrobust()
- * - pthread_mutexattr_setrobust()
  */
 
 /**
@@ -161,7 +159,12 @@
      * Currently, winpthreads only supports `PTHREAD_PROCESS_PRIVATE`.
      */
     int Shared          : 1;
-    int Reserved        : 3;
+    /**
+     * Zero for `PTHREAD_MUTEX_STALLED` and non-zero for
+     * `PTHREAD_MUTEX_ROBUST`.
+     */
+    int Robust          : 1;
+    int Reserved        : 2;
     /**
      * Can be one of the following values:
      *
@@ -199,6 +202,7 @@
 #define WINPTHREADS_MUTEX_ATTRIBUTES_DEFAULT ((WinpthreadsMutexAttributes) { \
     .Attributes.Type            = PTHREAD_MUTEX_NORMAL,                      \
     .Attributes.Shared          = PTHREAD_PROCESS_PRIVATE,                   \
+    .Attributes.Robust          = PTHREAD_MUTEX_STALLED,                     \
     .Attributes.Reserved        = 0,                                         \
     .Attributes.Protocol        = PTHREAD_PRIO_NONE,                         \
     .Attributes.PriorityCeiling = THREAD_PRIORITY_NORMAL,                    \
@@ -434,7 +438,8 @@
 }
 
 /*******************************************************************************
- * Normal Mutex (PTHREAD_MUTEX_NORMAL) implementation.
+ * Normal (PTHREAD_MUTEX_NORMAL) Stalled (PTHREAD_MUTEX_STALLED) Mutex
+ * implementation.
  *
  * Normal Mutexes have the following properties:
  *
@@ -545,7 +550,8 @@
 };
 
 /*******************************************************************************
- * Error Checking Mutex (PTHREAD_MUTEX_ERRORCHECK) implementation.
+ * Error Checking (PTHREAD_MUTEX_ERRORCHECK) Stalled (PTHREAD_MUTEX_STALLED)
+ * Mutex implementation.
  *
  * Error Checking Mutexes have the following properties:
  *
@@ -676,7 +682,8 @@
 };
 
 /*******************************************************************************
- * Recursive Mutex (PTHREAD_MUTEX_RECURSIVE) implementation.
+ * Recursive (PTHREAD_MUTEX_RECURSIVE) Stalled (PTHREAD_MUTEX_STALLED) Mutex
+ * implementation.
  *
  * Recursive Mutexes have the following properties:
  *
@@ -1043,6 +1050,44 @@
   return EINVAL;
 }
 
+int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int value)
+{
+  if (a == NULL) {
+    return EINVAL;
+  }
+
+  WinpthreadsMutexAttributes *wMutexAttr = (WinpthreadsMutexAttributes *) a;
+
+  if (wMutexAttr->Attributes.Magic != WINPTHREADS_MUTEX_ATTRIBUTES_MAGIC) {
+    return EINVAL;
+  }
+
+  switch (value) {
+    case PTHREAD_MUTEX_STALLED:
+    case PTHREAD_MUTEX_ROBUST:
+      wMutexAttr->Attributes.Robust = value;
+      return 0;
+  }
+
+  return EINVAL;
+}
+
+int pthread_mutexattr_getrobust(const pthread_mutexattr_t *a, int *value)
+{
+  if (a == NULL || value == NULL) {
+    return EINVAL;
+  }
+
+  const WinpthreadsMutexAttributes *wMutexAttr = (const WinpthreadsMutexAttributes *) a;
+
+  if (wMutexAttr->Attributes.Magic != WINPTHREADS_MUTEX_ATTRIBUTES_MAGIC) {
+    return EINVAL;
+  }
+
+  *value = !!wMutexAttr->Attributes.Robust;
+  return 0;
+}
+
 /*******************************************************************************
  * Implementation for public `pthread_mutex_*` functions.
  */
@@ -1148,6 +1193,10 @@
       return EINVAL;
     }
 
+    if (pthread_mutexattr_getrobust (&wMutexAttr.Value, &value) != 0) {
+      return EINVAL;
+    }
+
     if (pthread_mutexattr_getprotocol (&wMutexAttr.Value, &value) != 0) {
       return EINVAL;
     }
@@ -1165,13 +1214,25 @@
 
   switch (wMutexAttr.Attributes.Type) {
     case PTHREAD_MUTEX_NORMAL:
-      wMutexVtable = &WinpthreadsNormalMutexVtable;
+      if (wMutexAttr.Attributes.Robust) {
+        return ENOSYS;
+      } else {
+        wMutexVtable = &WinpthreadsNormalMutexVtable;
+      }
       break;
     case PTHREAD_MUTEX_ERRORCHECK:
-      wMutexVtable = &WinpthreadsErrorCheckMutexVtable;
+      if (wMutexAttr.Attributes.Robust) {
+        return ENOSYS;
+      } else {
+        wMutexVtable = &WinpthreadsErrorCheckMutexVtable;
+      }
       break;
     case PTHREAD_MUTEX_RECURSIVE:
-      wMutexVtable = &WinpthreadsRecursiveMutexVtable;
+      if (wMutexAttr.Attributes.Robust) {
+        return ENOSYS;
+      } else {
+        wMutexVtable = &WinpthreadsRecursiveMutexVtable;
+      }
       break;
     default:
       UNREACHABLE ();
diff --git a/mingw-w64-libraries/winpthreads/tests/Makefile.am b/mingw-w64-libraries/winpthreads/tests/Makefile.am
index 8087899..57a647d 100644
--- a/mingw-w64-libraries/winpthreads/tests/Makefile.am
+++ b/mingw-w64-libraries/winpthreads/tests/Makefile.am
@@ -113,6 +113,7 @@
 	pthread_mutex/attr-prioceiling                 \
 	pthread_mutex/attr-protocol                    \
 	pthread_mutex/attr-pshared                     \
+	pthread_mutex/attr-robust                      \
 	pthread_mutex/attr-type                        \
 	pthread_mutex/default-basic                    \
 	pthread_mutex/default-lock-recursive           \
diff --git a/mingw-w64-libraries/winpthreads/tests/pthread_mutex/attr-robust.c b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/attr-robust.c
new file mode 100644
index 0000000..39974c4
--- /dev/null
+++ b/mingw-w64-libraries/winpthreads/tests/pthread_mutex/attr-robust.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:
+ *
+ * Test functions `pthread_mutexattr_setrobust` and
+ * `pthread_mutexattr_getrobust`.
+ */
+
+static void DoTest (int value, int expectedValue, int expectedReturn1, int expectedReturn2) {
+  pthread_mutexattr_t mutexAttr;
+  pthread_mutex_t mutex;
+
+  assert (pthread_mutexattr_init (&mutexAttr) == 0);
+  assert (pthread_mutexattr_setrobust (&mutexAttr, value) == expectedReturn1);
+  assert (pthread_mutexattr_getrobust (&mutexAttr, &value) == 0);
+  assert (value == expectedValue);
+  assert (pthread_mutex_init (&mutex, &mutexAttr) == expectedReturn2);
+  if (expectedReturn2 == 0) {
+    assert (pthread_mutex_destroy (&mutex) == 0);
+  }
+  assert (pthread_mutexattr_destroy (&mutexAttr) == 0);
+}
+
+int main (void) {
+  DoTest (PTHREAD_MUTEX_STALLED, PTHREAD_MUTEX_STALLED, 0, 0);
+  DoTest (PTHREAD_MUTEX_ROBUST, PTHREAD_MUTEX_ROBUST, 0, ENOSYS);
+
+  /**
+   * Try setting an invalid value; default attribute value must be used.
+   */
+  DoTest (0xFF, PTHREAD_MUTEX_STALLED, EINVAL, 0);
+
+  return 0;
+}