Add sys_membarrier() dynamic detection, old liburcu.so -> liburcu-signal.so
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Wed, 13 Jan 2010 18:02:21 +0000 (13:02 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Wed, 13 Jan 2010 18:02:21 +0000 (13:02 -0500)
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 <mathieu.desnoyers@polymtl.ca>
Makefile.am
README
tests/Makefile.am
tests/urcutorture.c
urcu-static.h
urcu.c

index b2f279f2bda1214c5c0f5c39dc7845f9e688be72..4f915e13bb31eece195a6a53ae3a48d7ace8f396 100644 (file)
@@ -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 ba9c16dbdd5f6dfb8f7b96ad719eafda11b8a02f..b3839e1a614a134c4960cc96824cefca83078d69 100644 (file)
--- a/README
+++ b/README
@@ -44,19 +44,11 @@ Usage of liburcu
 
        * #include <urcu.h>
        * 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 <urcu.h>
-       * 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 <urcu.h>
+       * 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 <urcu-signal.h>
+       * 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 <urcu-bp.h>
index 10b7fab5f6a18bb7114cce5b0737c2ea0338e7ca..02e0583c08c3a8f3be1d9081a1fabe390d894ac6 100644 (file)
@@ -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)
index 7bebf6acf128c48c442a521f979101c285da044c..63fa386b4f84449f1b7105007a79f32457a79995 100644 (file)
@@ -8,7 +8,12 @@
 #include "api.h"
 #define _LGPL_SOURCE
 
+#ifdef TORTURE_RCU_MEMBARRIER
+#define RCU_MEMBARRIER
+#include <urcu.h>
+#endif
 #ifdef TORTURE_URCU_SIGNAL
+#define RCU_SIGNAL
 #include <urcu.h>
 #endif
 #ifdef TORTURE_URCU_MB
index d46613196f5d471b21e584a85c0eaa7f60154e18..853c327d5eec3fb49b6e2ea4997c981379925571 100644 (file)
 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 <unistd.h>
+#include <sys/syscall.h>
+
+/* 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 53dfbd5286e4ea5a02044fe23a17425fe738cc4f..67a3eb21c8996b0751f9fc1d14ed9d71379f8bf5 100644 (file)
--- 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 <stdio.h>
 #include <pthread.h>
 #include <signal.h>
 /* 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(&registry));
 }
-#endif /* #ifndef RCU_MB */
+#endif /* #ifdef RCU_SIGNAL */
This page took 0.03182 seconds and 4 git commands to generate.