Fix: dynamic fallback to compat futex on sys_futex ENOSYS
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 11 Sep 2015 14:33:43 +0000 (10:33 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Sun, 13 Sep 2015 16:38:17 +0000 (12:38 -0400)
Some MIPS processors (e.g. Cavium Octeon II) dynamically check if the
CPU supports ll/sc within sys_futex, and return a ENOSYS errno if they
don't, even though the architecture implements sys_futex.

Handle this situation by always building the sys_futex compatibility
layer, and fall-back on it if sys_futex return a ENOSYS errno. This is
a tiny compat layer which adds very little space overhead.

This adds an unlikely branch on return from sys_futex, which should
not be an issue performance-wise (we've already taken a system call).

Since this is a fall-back mode, don't try to be clever, and don't cache
the result, so that the common cases (architectures with a properly
working sys_futex) don't get two conditional branches, just one.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
CC: Michael Jeanson <mjeanson@efficios.com>
CC: Jon Bernard <jbernard@debian.org>
Makefile.am
urcu/futex.h

index 30a44ce66ab9f788f81f393f90ca0e905e0b31ac..2c971d7ce54a9867d95222680add2c9ae4c6dc45 100644 (file)
@@ -37,9 +37,7 @@ else
 COMPAT=
 endif
 
-if COMPAT_FUTEX
 COMPAT+=compat_futex.c
-endif
 
 RCULFHASH = rculfhash.c rculfhash-mm-order.c rculfhash-mm-chunk.c \
                rculfhash-mm-mmap.c
index 4d30faa31fad6d576af58a65ca75da6f135f526d..13d2b1a0a9c73904563e2b9b46d40d19e3316686 100644 (file)
@@ -47,22 +47,66 @@ extern "C" {
  * (returns EINTR).
  */
 
-#ifdef CONFIG_RCU_HAVE_FUTEX
-#include <syscall.h>
-#define futex(...)     syscall(__NR_futex, __VA_ARGS__)
-#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3)   \
-               futex(uaddr, op, val, timeout, uaddr2, val3)
-#define futex_async(uaddr, op, val, timeout, uaddr2, val3)     \
-               futex(uaddr, op, val, timeout, uaddr2, val3)
-#else
 extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
-       const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
-#define futex_noasync(uaddr, op, val, timeout, uaddr2, val3)   \
-               compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3)
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
 extern int compat_futex_async(int32_t *uaddr, int op, int32_t val,
-       const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
-#define futex_async(uaddr, op, val, timeout, uaddr2, val3)     \
-               compat_futex_async(uaddr, op, val, timeout, uaddr2, val3)
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3);
+
+#ifdef CONFIG_RCU_HAVE_FUTEX
+
+#include <unistd.h>
+#include <errno.h>
+#include <urcu/compiler.h>
+#include <urcu/syscall-compat.h>
+
+static inline int futex(int32_t *uaddr, int op, int32_t val,
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+       return syscall(__NR_futex, uaddr, op, val, timeout,
+                       uaddr2, val3);
+}
+
+static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+       int ret;
+
+       ret = futex(uaddr, op, val, timeout, uaddr2, val3);
+       if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
+               return compat_futex_noasync(uaddr, op, val, timeout,
+                               uaddr2, val3);
+       }
+       return ret;
+
+}
+
+static inline int futex_async(int32_t *uaddr, int op, int32_t val,
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+       int ret;
+
+       ret = futex(uaddr, op, val, timeout, uaddr2, val3);
+       if (caa_unlikely(ret < 0 && errno == ENOSYS)) {
+               return compat_futex_async(uaddr, op, val, timeout,
+                               uaddr2, val3);
+       }
+       return ret;
+}
+
+#else
+
+static inline int futex_noasync(int32_t *uaddr, int op, int32_t val,
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+       return compat_futex_noasync(uaddr, op, val, timeout, uaddr2, val3);
+}
+
+static inline int futex_async(int32_t *uaddr, int op, int32_t val,
+               const struct timespec *timeout, int32_t *uaddr2, int32_t val3)
+{
+       return compat_futex_async(uaddr, op, val, timeout, uaddr2, val3);
+}
+
 #endif
 
 #ifdef __cplusplus 
This page took 0.026839 seconds and 4 git commands to generate.