Allow forcing the use of sys membarrier
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 16 Sep 2016 19:15:41 +0000 (15:15 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 16 Sep 2016 19:56:28 +0000 (15:56 -0400)
When using the default (liburcu.so) and bulletproof (liburcu-bp.so)
flavours of Userspace RCU, kernel support for sys-membarrier is detected
dynamically and stored in the rcu_has_sys_membarrier_memb and
urcu_bp_has_sys_membarrier global variables.

Checking the value of these variables adds a small but measurable overhead
to smp_mb_slave. On systems which support sys-membarrier, it would be
nice to have a way of avoiding that overhead.

Here is the proposed approach: if CONFIG_RCU_FORCE_SYS_MEMBARRIER is
defined then rcu_has_sys_membarrier_memb/urcu_bp_has_sys_membarrier are
replaced with the constant 1, eliminating the overhead in smp_mb_slave.
As a sanity check, support for sys-membarrier is still detected at
startup. A program using liburcu or liburcu-bp compiled with this option
aborts in the library constructor if the membarrier system call is not
supported by the operating system.

Suggested-by: Duncan Sands <duncan.sands@deepbluecap.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
README.md
configure.ac
include/urcu/map/urcu.h
include/urcu/static/urcu-bp.h
include/urcu/static/urcu.h
src/urcu-bp.c
src/urcu.c

index 6fe9c1e..7ce0edf 100644 (file)
--- a/README.md
+++ b/README.md
@@ -159,7 +159,11 @@ This is the preferred version of the library, in terms of
 grace-period detection speed, read-side speed and flexibility.
 Dynamically detects kernel support for `sys_membarrier()`. Falls back
 on `urcu-mb` scheme if support is not present, which has slower
-read-side.
+read-side. Use the --disable-sys-membarrier-fallback configure option
+to disable the fall back, thus requiring `sys_membarrier()` to be
+available. This gives a small speedup when `sys_membarrier()` is
+supported by the kernel, and aborts in the library constructor if not
+supported.
 
 
 ### Usage of `liburcu-qsbr`
index 7a992ed..8ac0c41 100644 (file)
@@ -25,6 +25,15 @@ AH_TEMPLATE([CONFIG_RCU_COMPAT_ARCH], [Compatibility mode for i386 which lacks c
 AH_TEMPLATE([CONFIG_RCU_ARM_HAVE_DMB], [Use the dmb instruction if available for use on ARM.])
 AH_TEMPLATE([CONFIG_RCU_TLS], [TLS provided by the compiler.])
 AH_TEMPLATE([CONFIG_RCU_HAVE_CLOCK_GETTIME], [clock_gettime() is detected.])
+AH_TEMPLATE([CONFIG_RCU_FORCE_SYS_MEMBARRIER], [Require the operating system to support the membarrier system call for default and bulletproof flavors.])
+
+# Allow requiring the operating system to support the membarrier system
+# call. Applies to default and bulletproof flavors.
+AC_ARG_ENABLE([sys-membarrier-fallback],
+       AS_HELP_STRING([--disable-sys-membarrier-fallback], [Abort if sys-membarrier is needed but not available rather than using a fallback.]),
+       [def_sys_membarrier_fallback=$enableval],
+       [def_sys_membarrier_fallback="yes"])
+AS_IF([test "x$def_sys_membarrier_fallback" != "xyes"], [AC_DEFINE([CONFIG_RCU_FORCE_SYS_MEMBARRIER], [1])])
 
 # Allow overriding storage used for TLS variables.
 AC_ARG_ENABLE([compiler-tls],
index 9a4bb1a..449513e 100644 (file)
@@ -80,9 +80,6 @@
 
 #define rcu_flavor                     rcu_flavor_memb
 
-/* Specific to MEMBARRIER flavor */
-#define rcu_has_sys_membarrier         rcu_has_sys_membarrier_memb
-
 #elif defined(RCU_SIGNAL)
 
 #define rcu_read_lock                  rcu_read_lock_sig
index 6e52d84..6bcfab4 100644 (file)
@@ -33,6 +33,7 @@
 #include <pthread.h>
 #include <unistd.h>
 
+#include <urcu/config.h>
 #include <urcu/compiler.h>
 #include <urcu/arch.h>
 #include <urcu/system.h>
@@ -102,7 +103,11 @@ struct rcu_reader {
  */
 extern DECLARE_URCU_TLS(struct rcu_reader *, rcu_reader);
 
+#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER
+#define urcu_bp_has_sys_membarrier     1
+#else
 extern int urcu_bp_has_sys_membarrier;
+#endif
 
 static inline void urcu_bp_smp_mb_slave(void)
 {
index 7048f99..20fc864 100644 (file)
@@ -34,6 +34,7 @@
 #include <unistd.h>
 #include <stdint.h>
 
+#include <urcu/config.h>
 #include <urcu/compiler.h>
 #include <urcu/arch.h>
 #include <urcu/system.h>
@@ -89,11 +90,15 @@ enum rcu_state {
  */
 
 #ifdef RCU_MEMBARRIER
-extern int rcu_has_sys_membarrier;
+#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER
+#define rcu_has_sys_membarrier_memb    1
+#else
+extern int rcu_has_sys_membarrier_memb;
+#endif
 
 static inline void smp_mb_slave(void)
 {
-       if (caa_likely(rcu_has_sys_membarrier))
+       if (caa_likely(rcu_has_sys_membarrier_memb))
                cmm_barrier();
        else
                cmm_smp_mb();
index 4b4fe45..81bb91a 100644 (file)
@@ -111,7 +111,9 @@ void __attribute__((constructor)) rcu_bp_init(void);
 static
 void __attribute__((destructor)) rcu_bp_exit(void);
 
+#ifndef CONFIG_RCU_FORCE_SYS_MEMBARRIER
 int urcu_bp_has_sys_membarrier;
+#endif
 
 /*
  * rcu_gp_lock ensures mutual exclusion between threads calling
@@ -578,6 +580,22 @@ void urcu_bp_thread_exit_notifier(void *rcu_key)
        rcu_bp_unregister(rcu_key);
 }
 
+#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER
+static
+void rcu_sys_membarrier_status(int available)
+{
+       if (!available)
+               abort();
+}
+#else
+static
+void rcu_sys_membarrier_status(int available)
+{
+       if (available)
+               urcu_bp_has_sys_membarrier = 1;
+}
+#endif
+
 static
 void rcu_bp_init(void)
 {
@@ -590,9 +608,8 @@ void rcu_bp_init(void)
                if (ret)
                        abort();
                ret = membarrier(MEMBARRIER_CMD_QUERY, 0);
-               if (ret >= 0 && (ret & MEMBARRIER_CMD_SHARED)) {
-                       urcu_bp_has_sys_membarrier = 1;
-               }
+               rcu_sys_membarrier_status(ret >= 0
+                               && (ret & MEMBARRIER_CMD_SHARED));
                initialized = 1;
        }
        mutex_unlock(&init_lock);
index ccd9706..a81b129 100644 (file)
@@ -77,7 +77,9 @@ enum membarrier_cmd {
 
 #ifdef RCU_MEMBARRIER
 static int init_done;
-int rcu_has_sys_membarrier;
+#ifndef CONFIG_RCU_FORCE_SYS_MEMBARRIER
+int rcu_has_sys_membarrier_memb;
+#endif
 
 void __attribute__((constructor)) rcu_init(void);
 #endif
@@ -160,7 +162,7 @@ static void mutex_unlock(pthread_mutex_t *mutex)
 #ifdef RCU_MEMBARRIER
 static void smp_mb_master(void)
 {
-       if (caa_likely(rcu_has_sys_membarrier))
+       if (caa_likely(rcu_has_sys_membarrier_memb))
                (void) membarrier(MEMBARRIER_CMD_SHARED, 0);
        else
                cmm_smp_mb();
@@ -532,6 +534,23 @@ void rcu_unregister_thread(void)
 }
 
 #ifdef RCU_MEMBARRIER
+
+#ifdef CONFIG_RCU_FORCE_SYS_MEMBARRIER
+static
+void rcu_sys_membarrier_status(int available)
+{
+       if (!available)
+               abort();
+}
+#else
+static
+void rcu_sys_membarrier_status(int available)
+{
+       if (available)
+               rcu_has_sys_membarrier_memb = 1;
+}
+#endif
+
 void rcu_init(void)
 {
        int ret;
@@ -540,9 +559,7 @@ void rcu_init(void)
                return;
        init_done = 1;
        ret = membarrier(MEMBARRIER_CMD_QUERY, 0);
-       if (ret >= 0 && (ret & MEMBARRIER_CMD_SHARED)) {
-               rcu_has_sys_membarrier = 1;
-       }
+       rcu_sys_membarrier_status(ret >= 0 && (ret & MEMBARRIER_CMD_SHARED));
 }
 #endif
 
This page took 0.066952 seconds and 4 git commands to generate.