[lttng-dev] [RFC PATCH urcu] Fix: dynamic fallback to compat futex on sys_futex ENOSYS

Mathieu Desnoyers mathieu.desnoyers at efficios.com
Fri Sep 11 10:48:38 EDT 2015


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 at efficios.com>
CC: Paul E. McKenney <paulmck at linux.vnet.ibm.com>
CC: Michael Jeanson <mjeanson at efficios.com>
CC: Jon Bernard <jbernard at debian.org>
---
 Makefile.am  |  2 --
 urcu/futex.h | 70 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 752510d..f9a8888 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,9 +41,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
diff --git a/urcu/futex.h b/urcu/futex.h
index 2be3bb6..13d2b1a 100644
--- a/urcu/futex.h
+++ b/urcu/futex.h
@@ -47,22 +47,66 @@ extern "C" {
  * (returns EINTR).
  */
 
+extern int compat_futex_noasync(int32_t *uaddr, int op, int32_t val,
+		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);
+
 #ifdef CONFIG_RCU_HAVE_FUTEX
+
+#include <unistd.h>
+#include <errno.h>
+#include <urcu/compiler.h>
 #include <urcu/syscall-compat.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)
+
+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
-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)
-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)
+
+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 
-- 
2.1.4




More information about the lttng-dev mailing list