From fdf01eeda9f634a32db3fc90cd342da08d7a259d Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 13 Jan 2010 13:02:21 -0500 Subject: [PATCH] Add sys_membarrier() dynamic detection, old liburcu.so -> liburcu-signal.so See updated README for library renaming details. liburcu is now dynamically detecting if sys_membarrier is available, and using urcu-mb as fall back. Signed-off-by: Mathieu Desnoyers --- Makefile.am | 9 ++-- README | 34 +++++++++------ tests/Makefile.am | 103 ++++++++++++++++++++++++++++---------------- tests/urcutorture.c | 5 +++ urcu-static.h | 43 +++++++++++++++--- urcu.c | 51 ++++++++++++++++++---- 6 files changed, 177 insertions(+), 68 deletions(-) diff --git a/Makefile.am b/Makefile.am index b2f279f..4f915e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,19 +23,22 @@ if COMPAT_FUTEX COMPAT+=compat_futex.c endif -lib_LTLIBRARIES = liburcu.la liburcu-mb.la liburcu-defer.la liburcu-qsbr.la liburcu-bp.la +lib_LTLIBRARIES = liburcu.la liburcu-qsbr.la liburcu-mb.la liburcu-signal.la liburcu-bp.la liburcu-defer.la liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) +liburcu_qsbr_la_SOURCES = urcu-qsbr.c urcu-pointer.c $(COMPAT) + liburcu_mb_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) liburcu_mb_la_CFLAGS = -DRCU_MB +liburcu_signal_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) +liburcu_signal_la_CFLAGS = -DRCU_SIGNAL + liburcu_bp_la_SOURCES = urcu-bp.c urcu-pointer.c $(COMPAT) liburcu_defer_la_SOURCES = urcu-defer.c $(COMPAT) -liburcu_qsbr_la_SOURCES = urcu-qsbr.c urcu-pointer.c $(COMPAT) - $(top_srcdir)/*.h $(top_srcdir)/*.c: urcu/arch.h urcu/uatomic_arch.h urcu/arch.h: $(top_srcdir)/urcu/arch_@ARCHTYPE@.h diff --git a/README b/README index ba9c16d..b3839e1 100644 --- a/README +++ b/README @@ -44,19 +44,11 @@ Usage of liburcu * #include * Link the application with "-lurcu". - * This is the preferred version of the library, both in terms of speed - and flexibility. Requires a signal, typically SIGUSR1. Can be - overridden with -DSIGRCU by modifying Makefile.build.inc. - -Usage of liburcu-mb - - * #include - * Compile any _LGPL_SOURCE code using this library with "-DRCU_MB". - * Link with "-lurcu-mb". - * This version of the urcu library does not need to - reserve a signal number. RCU_MB uses full memory barriers for - readers. This eliminates the need for signals but results in slower - reads. + * 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. Usage of liburcu-qsbr @@ -68,6 +60,22 @@ Usage of liburcu-qsbr the threads are not active. It provides the fastest read-side at the expense of more intrusiveness in the application code. +Usage of liburcu-mb + + * #include + * Compile any _LGPL_SOURCE code using this library with "-DRCU_MB". + * Link with "-lurcu-mb". + * This version of the urcu library uses memory barriers on the writer + and reader sides. This results in faster grace-period detection, but + results in slower reads. + +Usage of liburcu-signal + + * #include + * Link the application with "-lurcu-signal". + * Version of the library that requires a signal, typically SIGUSR1. Can + be overridden with -DSIGRCU by modifying Makefile.build.inc. + Usage of liburcu-bp * #include diff --git a/tests/Makefile.am b/tests/Makefile.am index 10b7fab..02e0583 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,13 +2,15 @@ AM_LDFLAGS=-lpthread AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \ + test_urcu_signal test_urcu_signal_dynamic_link test_urcu_signal_timing \ test_rwlock_timing test_rwlock test_perthreadlock_timing \ - test_perthreadlock test_urcu_yield test_urcu_mb \ - test_qsbr_timing test_qsbr rcutorture_urcu \ + test_perthreadlock test_urcu_yield test_urcu_signal_yield test_urcu_mb \ + test_qsbr_timing test_qsbr rcutorture_urcu rcutorture_urcu_signal \ rcutorture_urcu_mb rcutorture_urcu_bp rcutorture_qsbr \ - test_mutex test_looplen test_urcu_gc \ - test_urcu_gc_mb test_qsbr_gc test_qsbr_lgc test_urcu_lgc \ - test_urcu_lgc_mb test_qsbr_dynamic_link test_urcu_mb_defer \ + test_mutex test_looplen test_urcu_gc test_urcu_signal_gc \ + test_urcu_lgc \ + test_urcu_mb_gc test_qsbr_gc test_qsbr_lgc test_urcu_signal_lgc \ + test_urcu_mb_lgc test_qsbr_dynamic_link test_urcu_defer \ test_uatomic test_urcu_assign test_urcu_assign_dynamic_link \ test_urcu_bp test_urcu_bp_dynamic_link noinst_HEADERS = rcutorture.h @@ -23,20 +25,20 @@ if COMPAT_FUTEX COMPAT+=$(top_srcdir)/compat_futex.c endif -URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) -# URCU_SIGNAL_YIELD uses urcu.c but -DDEBUG_YIELD must be defined -URCU_SIGNAL_YIELD=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) +URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) +URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(COMPAT) # URCU_MB uses urcu.c but -DRCU_MB must be defined URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) +# URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined +URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(COMPAT) URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(COMPAT) -URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(COMPAT) -# -DRCU_MB must be defined -URCU_MB_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-defer.c $(top_srcdir)/urcu-pointer.c $(COMPAT) +URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-defer.c $(top_srcdir)/urcu-pointer.c $(COMPAT) -URCU_SIGNAL_LIB=$(top_builddir)/liburcu.la +URCU_LIB=$(top_builddir)/liburcu.la +URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la URCU_MB_LIB=$(top_builddir)/liburcu-mb.la +URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la URCU_BP_LIB=$(top_builddir)/liburcu-bp.la -URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la if GCC_API APIHEADER=api_gcc.h @@ -47,34 +49,52 @@ endif EXTRA_DIST = $(top_srcdir)/tests/api_*.h -test_urcu_SOURCES = test_urcu.c $(URCU_SIGNAL) +test_urcu_SOURCES = test_urcu.c $(URCU) -test_urcu_dynamic_link_SOURCES = test_urcu.c $(URCU_SIGNAL) +test_urcu_dynamic_link_SOURCES = test_urcu.c $(URCU) test_urcu_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS) -test_urcu_timing_SOURCES = test_urcu_timing.c $(URCU_SIGNAL) +test_urcu_timing_SOURCES = test_urcu_timing.c $(URCU) -test_rwlock_timing_SOURCES = test_rwlock_timing.c $(URCU_SIGNAL) +test_urcu_yield_SOURCES = test_urcu.c $(URCU) +test_urcu_yield_CFLAGS = -DDEBUG_YIELD $(AM_CFLAGS) -test_rwlock_SOURCES = test_rwlock.c $(URCU_SIGNAL) -test_perthreadlock_timing_SOURCES = test_perthreadlock_timing.c $(URCU_SIGNAL) +test_qsbr_SOURCES = test_qsbr.c $(URCU_QSBR) -test_perthreadlock_SOURCES = test_perthreadlock.c $(URCU_SIGNAL) +test_qsbr_timing_SOURCES = test_qsbr_timing.c $(URCU_QSBR) -test_urcu_yield_SOURCES = test_urcu.c $(URCU_SIGNAL_YIELD) -test_urcu_yield_CFLAGS = -DDEBUG_YIELD $(AM_CFLAGS) test_urcu_mb_SOURCES = test_urcu.c $(URCU_MB) test_urcu_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS) -test_qsbr_timing_SOURCES = test_qsbr_timing.c $(URCU_QSBR) -test_qsbr_SOURCES = test_qsbr.c $(URCU_QSBR) +test_urcu_signal_SOURCES = test_urcu.c $(URCU_SIGNAL) +test_urcu_signal_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS) + +test_urcu_signal_dynamic_link_SOURCES = test_urcu.c $(URCU_SIGNAL) +test_urcu_signal_dynamic_link_CFLAGS = -DRCU_SIGNAL -DDYNAMIC_LINK_TEST \ + $(AM_CFLAGS) + +test_urcu_signal_timing_SOURCES = test_urcu_timing.c $(URCU_SIGNAL) +test_urcu_signal_timing_CFLAGS= -DRCU_SIGNAL $(AM_CFLAGS) + +test_urcu_signal_yield_SOURCES = test_urcu.c $(URCU_SIGNAL) +test_urcu_signal_yield_CFLAGS = -DRCU_SIGNAL -DDEBUG_YIELD $(AM_CFLAGS) + + +test_rwlock_timing_SOURCES = test_rwlock_timing.c $(URCU_SIGNAL) + +test_rwlock_SOURCES = test_rwlock.c $(URCU_SIGNAL) + +test_perthreadlock_timing_SOURCES = test_perthreadlock_timing.c $(URCU_SIGNAL) + +test_perthreadlock_SOURCES = test_perthreadlock.c $(URCU_SIGNAL) + rcutorture_urcu_SOURCES = urcutorture.c -rcutorture_urcu_CFLAGS = -DTORTURE_URCU_SIGNAL $(AM_CFLAGS) -rcutorture_urcu_LDADD = $(URCU_SIGNAL_LIB) +rcutorture_urcu_CFLAGS = -DTORTURE_URCU $(AM_CFLAGS) +rcutorture_urcu_LDADD = $(URCU) rcutorture_urcu_mb_SOURCES = urcutorture.c rcutorture_urcu_mb_CFLAGS = -DTORTURE_URCU_MB $(AM_CFLAGS) @@ -84,41 +104,50 @@ rcutorture_qsbr_SOURCES = urcutorture.c rcutorture_qsbr_CFLAGS = -DTORTURE_QSBR $(AM_CFLAGS) rcutorture_qsbr_LDADD = $(URCU_QSBR_LIB) +rcutorture_urcu_signal_SOURCES = urcutorture.c +rcutorture_urcu_signal_CFLAGS = -DTORTURE_URCU_SIGNAL $(AM_CFLAGS) +rcutorture_urcu_signal_LDADD = $(URCU_SIGNAL_LIB) + rcutorture_urcu_bp_SOURCES = urcutorture.c rcutorture_urcu_bp_CFLAGS = -DTORTURE_URCU_BP $(AM_CFLAGS) rcutorture_urcu_bp_LDADD = $(URCU_BP_LIB) -test_mutex_SOURCES = test_mutex.c $(URCU_SIGNAL) +test_mutex_SOURCES = test_mutex.c $(URCU) test_looplen_SOURCES = test_looplen.c -test_urcu_gc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL) +test_urcu_gc_SOURCES = test_urcu_gc.c $(URCU) -test_urcu_gc_mb_SOURCES = test_urcu_gc.c $(URCU_MB) -test_urcu_gc_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS) +test_urcu_signal_gc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL) +test_urcu_signal_gc_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS) + +test_urcu_mb_gc_SOURCES = test_urcu_gc.c $(URCU_MB) +test_urcu_mb_gc_CFLAGS = -DRCU_MB $(AM_CFLAGS) test_qsbr_gc_SOURCES = test_qsbr_gc.c $(URCU_QSBR) test_qsbr_lgc_SOURCES = test_qsbr_gc.c $(URCU_QSBR) test_qsbr_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS) -test_urcu_lgc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL) +test_urcu_lgc_SOURCES = test_urcu_gc.c $(URCU) test_urcu_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS) -test_urcu_lgc_mb_SOURCES = test_urcu_gc.c $(URCU_MB) -test_urcu_lgc_mb_CFLAGS = -DTEST_LOCAL_GC -DRCU_MB $(AM_CFLAGS) +test_urcu_signal_lgc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL) +test_urcu_signal_lgc_CFLAGS = -DRCU_SIGNAL -DTEST_LOCAL_GC $(AM_CFLAGS) + +test_urcu_mb_lgc_SOURCES = test_urcu_gc.c $(URCU_MB) +test_urcu_mb_lgc_CFLAGS = -DTEST_LOCAL_GC -DRCU_MB $(AM_CFLAGS) test_qsbr_dynamic_link_SOURCES = test_qsbr.c $(URCU_QSBR) test_qsbr_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS) -test_urcu_mb_defer_SOURCES = test_urcu_defer.c $(URCU_MB_DEFER) -test_urcu_mb_defer_CFLAGS = -DRCU_MB $(AM_CFLAGS) +test_urcu_defer_SOURCES = test_urcu_defer.c $(URCU_DEFER) test_uatomic_SOURCES = test_uatomic.c $(COMPAT) -test_urcu_assign_SOURCES = test_urcu_assign.c $(URCU_SIGNAL) +test_urcu_assign_SOURCES = test_urcu_assign.c $(URCU) -test_urcu_assign_dynamic_link_SOURCES = test_urcu_assign.c $(URCU_SIGNAL) +test_urcu_assign_dynamic_link_SOURCES = test_urcu_assign.c $(URCU) test_urcu_assign_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS) test_urcu_bp_SOURCES = test_urcu_bp.c $(URCU_BP) diff --git a/tests/urcutorture.c b/tests/urcutorture.c index 7bebf6a..63fa386 100644 --- a/tests/urcutorture.c +++ b/tests/urcutorture.c @@ -8,7 +8,12 @@ #include "api.h" #define _LGPL_SOURCE +#ifdef TORTURE_RCU_MEMBARRIER +#define RCU_MEMBARRIER +#include +#endif #ifdef TORTURE_URCU_SIGNAL +#define RCU_SIGNAL #include #endif #ifdef TORTURE_URCU_MB diff --git a/urcu-static.h b/urcu-static.h index d466131..853c327 100644 --- a/urcu-static.h +++ b/urcu-static.h @@ -45,6 +45,24 @@ extern "C" { #endif +/* Default is RCU_MEMBARRIER */ +#if !defined(RCU_MEMBARRIER) && !defined(RCU_MB) && !defined(RCU_SIGNAL) +#define RCU_MEMBARRIER +#endif + +#ifdef RCU_MEMBARRIER +#include +#include + +/* If the headers do not support SYS_membarrier, statically use RCU_MB */ +#ifdef SYS_membarrier +#define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__) +#else +#undef RCU_MEMBARRIER +#define RCU_MB +#endif +#endif + /* * This code section can only be included in LGPL 2.1 compatible source code. * See below for the function call wrappers which can be used in code meant to @@ -89,14 +107,13 @@ extern "C" { #define YIELD_WRITE (1 << 1) /* - * Updates without RCU_MB are much slower. Account this in - * the delay. + * Updates with RCU_SIGNAL are much slower. Account this in the delay. */ -#ifdef RCU_MB +#ifdef RCU_SIGNAL /* maximum sleep delay, in us */ -#define MAX_SLEEP 50 -#else #define MAX_SLEEP 30000 +#else +#define MAX_SLEEP 50 #endif extern unsigned int yield_active; @@ -135,12 +152,26 @@ static inline void debug_yield_init(void) } #endif +#ifdef RCU_MEMBARRIER +extern int has_sys_membarrier; + +static inline void smp_mb_light() +{ + if (likely(has_sys_membarrier)) + barrier(); + else + smp_mb(); +} +#endif + #ifdef RCU_MB static inline void smp_mb_light() { smp_mb(); } -#else +#endif + +#ifdef RCU_SIGNAL static inline void smp_mb_light() { barrier(); diff --git a/urcu.c b/urcu.c index 53dfbd5..67a3eb2 100644 --- a/urcu.c +++ b/urcu.c @@ -23,6 +23,7 @@ * IBM's contributions to this file may be relicensed under LGPLv2 or later. */ +#define _BSD_SOURCE #include #include #include @@ -36,17 +37,26 @@ /* Do not #define _LGPL_SOURCE to ensure we can emit the wrapper symbols */ #include "urcu.h" -#ifndef RCU_MB +#ifdef RCU_MEMBARRIER static int init_done; +int has_sys_membarrier; void __attribute__((constructor)) rcu_init(void); -void __attribute__((destructor)) rcu_exit(void); -#else +#endif + +#ifdef RCU_MB void rcu_init(void) { } #endif +#ifdef RCU_SIGNAL +static int init_done; + +void __attribute__((constructor)) rcu_init(void); +void __attribute__((destructor)) rcu_exit(void); +#endif + static pthread_mutex_t rcu_mutex = PTHREAD_MUTEX_INITIALIZER; int gp_futex; @@ -118,12 +128,24 @@ static void switch_next_rcu_qparity(void) STORE_SHARED(rcu_gp_ctr, rcu_gp_ctr ^ RCU_GP_CTR_PHASE); } +#ifdef RCU_MEMBARRIER +static void smp_mb_heavy(void) +{ + if (likely(has_sys_membarrier)) + membarrier(1); + else + smp_mb(); +} +#endif + #ifdef RCU_MB -static void smp_mb_heavy() +static void smp_mb_heavy(void) { smp_mb(); } -#else +#endif + +#ifdef RCU_SIGNAL static void force_mb_all_readers(void) { struct rcu_reader *index; @@ -167,11 +189,11 @@ static void force_mb_all_readers(void) smp_mb(); /* read ->need_mb before ending the barrier */ } -static void smp_mb_heavy() +static void smp_mb_heavy(void) { force_mb_all_readers(); } -#endif /* #else #ifdef RCU_MB */ +#endif /* #ifdef RCU_SIGNAL */ /* * synchronize_rcu() waiting. Single thread. @@ -364,7 +386,18 @@ void rcu_unregister_thread(void) internal_rcu_unlock(); } -#ifndef RCU_MB +#ifdef RCU_MEMBARRIER +void rcu_init(void) +{ + if (init_done) + return; + init_done = 1; + if (!membarrier(1)) + has_sys_membarrier = 1; +} +#endif + +#ifdef RCU_SIGNAL static void sigrcu_handler(int signo, siginfo_t *siginfo, void *context) { /* @@ -417,4 +450,4 @@ void rcu_exit(void) assert(act.sa_sigaction == sigrcu_handler); assert(list_empty(®istry)); } -#endif /* #ifndef RCU_MB */ +#endif /* #ifdef RCU_SIGNAL */ -- 2.34.1