From d8d9a3405ce46af6d34d2e80e260ad50f3d211a0 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 16 Sep 2016 15:15:41 -0400 Subject: [PATCH] Allow forcing the use of sys membarrier 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 Signed-off-by: Mathieu Desnoyers --- README.md | 6 +++++- configure.ac | 9 +++++++++ include/urcu/map/urcu.h | 3 --- include/urcu/static/urcu-bp.h | 5 +++++ include/urcu/static/urcu.h | 9 +++++++-- src/urcu-bp.c | 23 ++++++++++++++++++++--- src/urcu.c | 27 ++++++++++++++++++++++----- 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6fe9c1e..7ce0edf 100644 --- 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` diff --git a/configure.ac b/configure.ac index 7a992ed..8ac0c41 100644 --- a/configure.ac +++ b/configure.ac @@ -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], diff --git a/include/urcu/map/urcu.h b/include/urcu/map/urcu.h index 9a4bb1a..449513e 100644 --- a/include/urcu/map/urcu.h +++ b/include/urcu/map/urcu.h @@ -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 diff --git a/include/urcu/static/urcu-bp.h b/include/urcu/static/urcu-bp.h index 6e52d84..6bcfab4 100644 --- a/include/urcu/static/urcu-bp.h +++ b/include/urcu/static/urcu-bp.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -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) { diff --git a/include/urcu/static/urcu.h b/include/urcu/static/urcu.h index 7048f99..20fc864 100644 --- a/include/urcu/static/urcu.h +++ b/include/urcu/static/urcu.h @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -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(); diff --git a/src/urcu-bp.c b/src/urcu-bp.c index 4b4fe45..81bb91a 100644 --- a/src/urcu-bp.c +++ b/src/urcu-bp.c @@ -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); diff --git a/src/urcu.c b/src/urcu.c index ccd9706..a81b129 100644 --- a/src/urcu.c +++ b/src/urcu.c @@ -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 -- 2.34.1