check for kernel support before allowing robust mutex creation
authorRich Felker <dalias@aerifal.cx>
Sat, 15 Sep 2018 17:45:41 +0000 (13:45 -0400)
committerRich Felker <dalias@aerifal.cx>
Sat, 15 Sep 2018 18:22:06 +0000 (14:22 -0400)
on some archs, linux support for futex operations (including
robust_list processing) that depend on kernelspace CAS is conditional
on a runtime check. as of linux 4.18, this check fails unconditionally
on nommu archs that perform it, and spurious failure on powerpc64 was
observed but not explained. it's also possible that futex support is
omitted entirely, or that the kernel is older than 2.6.17. for most
futex ops, ENOSYS does not yield hard breakage; userspace will just
spin at 100% cpu load. but for robust mutexes, correct behavior
depends on the kernel functionality.

use the get_robust_list syscall to probe for support at the first call
to pthread_mutexattr_setrobust, and block creation of robust mutexes
with a reportable error if they can't be supported.

src/thread/pthread_mutexattr_setrobust.c

index dcfa4cf1c771c5347240c3bd826448b69f094f06..04db92a626dbd0b05eac4bcd88363a6e31e54207 100644 (file)
@@ -1,9 +1,25 @@
 #include "pthread_impl.h"
+#include "syscall.h"
+
+static pthread_once_t check_robust_once;
+static int check_robust_result;
+
+static void check_robust()
+{
+       void *p;
+       size_t l;
+       check_robust_result = -__syscall(SYS_get_robust_list, 0, &p, &l);
+}
 
 int pthread_mutexattr_setrobust(pthread_mutexattr_t *a, int robust)
 {
        if (robust > 1U) return EINVAL;
+       if (robust) {
+               pthread_once(&check_robust_once, check_robust);
+               if (check_robust_result) return check_robust_result;
+               a->__attr |= 4;
+               return 0;
+       }
        a->__attr &= ~4;
-       a->__attr |= robust*4;
        return 0;
 }