Add rcu_read_ongoing() API to each urcu flavor
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 30 Apr 2013 00:17:22 +0000 (20:17 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 30 Apr 2013 00:17:22 +0000 (20:17 -0400)
This will allow checking whether:

- thread is online (QSBR),
- thread is nested within read-side critical section (other flavors),

This is useful for libraries that need to know if QSBR is online in
order to save the original state temporarily so it can be restored
before returning to the caller.

Eventually, this API can be called by a "debugging" implementation of
rcu_dereference() and other urcu-pointer.h API members to check that no
RCU pointer is read outside of RCU read-side critical sections.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
16 files changed:
tests/test_urcu.c
tests/test_urcu_bp.c
tests/test_urcu_qsbr.c
urcu-bp.c
urcu-bp.h
urcu-flavor.h
urcu-qsbr.c
urcu-qsbr.h
urcu.c
urcu.h
urcu/map/urcu-bp.h
urcu/map/urcu-qsbr.h
urcu/map/urcu.h
urcu/static/urcu-bp.h
urcu/static/urcu-qsbr.h
urcu/static/urcu.h

index 3c5c492..5059dde 100644 (file)
@@ -187,6 +187,7 @@ void *thr_reader(void *_count)
        set_affinity();
 
        rcu_register_thread();
+       assert(!rcu_read_ongoing());
 
        while (!test_go)
        {
@@ -195,6 +196,7 @@ void *thr_reader(void *_count)
 
        for (;;) {
                rcu_read_lock();
+               assert(rcu_read_ongoing());
                local_ptr = rcu_dereference(test_rcu_pointer);
                rcu_debug_yield_read();
                if (local_ptr)
index 8cb74ff..1926fbb 100644 (file)
@@ -187,6 +187,7 @@ void *thr_reader(void *_count)
        set_affinity();
 
        rcu_register_thread();
+       assert(!rcu_read_ongoing());
 
        while (!test_go)
        {
@@ -195,6 +196,7 @@ void *thr_reader(void *_count)
 
        for (;;) {
                rcu_read_lock();
+               assert(rcu_read_ongoing());
                local_ptr = rcu_dereference(test_rcu_pointer);
                rcu_debug_yield_read();
                if (local_ptr)
index 065557a..f98e273 100644 (file)
@@ -187,6 +187,11 @@ void *thr_reader(void *_count)
 
        rcu_register_thread();
 
+       assert(rcu_read_ongoing());
+       rcu_thread_offline();
+       assert(!rcu_read_ongoing());
+       rcu_thread_online();
+
        while (!test_go)
        {
        }
@@ -194,6 +199,7 @@ void *thr_reader(void *_count)
 
        for (;;) {
                rcu_read_lock();
+               assert(rcu_read_ongoing());
                local_ptr = rcu_dereference(test_rcu_pointer);
                rcu_debug_yield_read();
                if (local_ptr)
index f99c0e5..8207a41 100644 (file)
--- a/urcu-bp.c
+++ b/urcu-bp.c
@@ -301,6 +301,11 @@ void rcu_read_unlock(void)
        _rcu_read_unlock();
 }
 
+int rcu_read_ongoing(void)
+{
+       return _rcu_read_ongoing();
+}
+
 /*
  * only grow for now.
  */
index 833688f..4718f3b 100644 (file)
--- a/urcu-bp.h
+++ b/urcu-bp.h
@@ -74,6 +74,7 @@ extern "C" {
  */
 #define rcu_read_lock_bp               _rcu_read_lock
 #define rcu_read_unlock_bp             _rcu_read_unlock
+#define rcu_read_ongoing_bp            _rcu_read_ongoing
 
 #define rcu_dereference_bp             rcu_dereference
 #define rcu_cmpxchg_pointer_bp         rcu_cmpxchg_pointer
@@ -89,6 +90,7 @@ extern "C" {
 
 extern void rcu_read_lock(void);
 extern void rcu_read_unlock(void);
+extern int rcu_read_ongoing(void);
 
 extern void *rcu_dereference_sym_bp(void *p);
 #define rcu_dereference_bp(p)                                               \
index 9af4d0e..c04f1db 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
 struct rcu_flavor_struct {
        void (*read_lock)(void);
        void (*read_unlock)(void);
+       int (*read_ongoing)(void);
        void (*read_quiescent_state)(void);
        void (*update_call_rcu)(struct rcu_head *head,
                                void (*func)(struct rcu_head *head));
@@ -46,6 +47,7 @@ struct rcu_flavor_struct {
 const struct rcu_flavor_struct x = {                   \
        .read_lock              = rcu_read_lock,        \
        .read_unlock            = rcu_read_unlock,      \
+       .read_ongoing           = rcu_read_ongoing,     \
        .read_quiescent_state   = rcu_quiescent_state,  \
        .update_call_rcu        = call_rcu,             \
        .update_synchronize_rcu = synchronize_rcu,      \
index 3c2c65d..786a80d 100644 (file)
@@ -208,7 +208,7 @@ void synchronize_rcu(void)
        DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING);
        struct urcu_waiters waiters;
 
-       was_online = URCU_TLS(rcu_reader).ctr;
+       was_online = rcu_read_ongoing();
 
        /* All threads should read qparity before accessing data structure
         * where new ptr points to.  In the "then" case, rcu_thread_offline
@@ -317,7 +317,7 @@ void synchronize_rcu(void)
        DEFINE_URCU_WAIT_NODE(wait, URCU_WAIT_WAITING);
        struct urcu_waiters waiters;
 
-       was_online = URCU_TLS(rcu_reader).ctr;
+       was_online = rcu_read_ongoing();
 
        /*
         * Mark the writer thread offline to make sure we don't wait for
@@ -405,6 +405,11 @@ void rcu_read_unlock(void)
        _rcu_read_unlock();
 }
 
+int rcu_read_ongoing(void)
+{
+       return _rcu_read_ongoing();
+}
+
 void rcu_quiescent_state(void)
 {
        _rcu_quiescent_state();
index a2f6575..bb0523c 100644 (file)
@@ -70,6 +70,7 @@ extern "C" {
  */
 #define rcu_read_lock_qsbr             _rcu_read_lock
 #define rcu_read_unlock_qsbr           _rcu_read_unlock
+#define rcu_read_ongoing_qsbr          _rcu_read_ongoing
 
 #define rcu_quiescent_state_qsbr       _rcu_quiescent_state
 #define rcu_thread_offline_qsbr                _rcu_thread_offline
@@ -107,6 +108,7 @@ extern void rcu_read_unlock(void);
 
 #endif /* !RCU_DEBUG */
 
+extern int rcu_read_ongoing(void);
 extern void rcu_quiescent_state(void);
 extern void rcu_thread_offline(void);
 extern void rcu_thread_online(void);
diff --git a/urcu.c b/urcu.c
index 15def09..a78c02b 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -429,6 +429,11 @@ void rcu_read_unlock(void)
        _rcu_read_unlock();
 }
 
+int rcu_read_ongoing(void)
+{
+       return _rcu_read_ongoing();
+}
+
 void rcu_register_thread(void)
 {
        URCU_TLS(rcu_reader).tid = pthread_self();
diff --git a/urcu.h b/urcu.h
index cd4fcbb..b8ca700 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -74,12 +74,15 @@ extern "C" {
 #ifdef RCU_MEMBARRIER
 #define rcu_read_lock_memb             _rcu_read_lock
 #define rcu_read_unlock_memb           _rcu_read_unlock
+#define rcu_read_ongoing_memb          _rcu_read_ongoing
 #elif defined(RCU_SIGNAL)
 #define rcu_read_lock_sig              _rcu_read_lock
 #define rcu_read_unlock_sig            _rcu_read_unlock
+#define rcu_read_ongoing_sig           _rcu_read_ongoing
 #elif defined(RCU_MB)
 #define rcu_read_lock_mb               _rcu_read_lock
 #define rcu_read_unlock_mb             _rcu_read_unlock
+#define rcu_read_ongoing_mb            _rcu_read_ongoing
 #endif
 
 #else /* !_LGPL_SOURCE */
@@ -91,6 +94,7 @@ extern "C" {
 
 extern void rcu_read_lock(void);
 extern void rcu_read_unlock(void);
+extern int rcu_read_ongoing(void);
 
 #endif /* !_LGPL_SOURCE */
 
index 63582fd..8c819a6 100644 (file)
@@ -38,6 +38,8 @@
 #define _rcu_read_lock                 _rcu_read_lock_bp
 #define rcu_read_unlock                        rcu_read_unlock_bp
 #define _rcu_read_unlock               _rcu_read_unlock_bp
+#define rcu_read_ongoing               rcu_read_ongoing_bp
+#define _rcu_read_ongoing              _rcu_read_ongoing_bp
 #define rcu_register_thread            rcu_register_thread_bp
 #define rcu_unregister_thread          rcu_unregister_thread_bp
 #define rcu_init                       rcu_init_bp
index f0aecc9..c40af35 100644 (file)
@@ -38,6 +38,8 @@
 #define _rcu_read_lock                 _rcu_read_lock_qsbr
 #define rcu_read_unlock                        rcu_read_unlock_qsbr
 #define _rcu_read_unlock               _rcu_read_unlock_qsbr
+#define rcu_read_ongoing               rcu_read_ongoing_qsbr
+#define _rcu_read_ongoing              _rcu_read_ongoing_qsbr
 #define rcu_quiescent_state            rcu_quiescent_state_qsbr
 #define _rcu_quiescent_state           _rcu_quiescent_state_qsbr
 #define rcu_thread_offline             rcu_thread_offline_qsbr
index 759cb41..becc6a0 100644 (file)
@@ -69,6 +69,8 @@
 #define _rcu_read_lock                 _rcu_read_lock_memb
 #define rcu_read_unlock                        rcu_read_unlock_memb
 #define _rcu_read_unlock               _rcu_read_unlock_memb
+#define rcu_read_ongoing               rcu_read_ongoing_memb
+#define _rcu_read_ongoing              _rcu_read_ongoing_memb
 #define rcu_register_thread            rcu_register_thread_memb
 #define rcu_unregister_thread          rcu_unregister_thread_memb
 #define rcu_init                       rcu_init_memb
 #define _rcu_read_lock                 _rcu_read_lock_sig
 #define rcu_read_unlock                        rcu_read_unlock_sig
 #define _rcu_read_unlock               _rcu_read_unlock_sig
+#define rcu_read_ongoing               rcu_read_ongoing_sig
+#define _rcu_read_ongoing              _rcu_read_ongoing_sig
 #define rcu_register_thread            rcu_register_thread_sig
 #define rcu_unregister_thread          rcu_unregister_thread_sig
 #define rcu_init                       rcu_init_sig
 #define _rcu_read_lock                 _rcu_read_lock_mb
 #define rcu_read_unlock                        rcu_read_unlock_mb
 #define _rcu_read_unlock               _rcu_read_unlock_mb
+#define rcu_read_ongoing               rcu_read_ongoing_mb
+#define _rcu_read_ongoing              _rcu_read_ongoing_mb
 #define rcu_register_thread            rcu_register_thread_mb
 #define rcu_unregister_thread          rcu_unregister_thread_mb
 #define rcu_init                       rcu_init_mb
index c7f5326..2f36520 100644 (file)
@@ -223,6 +223,20 @@ static inline void _rcu_read_unlock(void)
        cmm_barrier();  /* Ensure the compiler does not reorder us with mutex */
 }
 
+/*
+ * Returns whether within a RCU read-side critical section.
+ *
+ * This function is less than 10 lines long.  The intent is that this
+ * function meets the 10-line criterion for LGPL, allowing this function
+ * to be invoked directly from non-LGPL code.
+ */
+static inline int _rcu_read_ongoing(void)
+{
+       if (caa_unlikely(!URCU_TLS(rcu_reader)))
+               rcu_bp_register(); /* If not yet registered. */
+       return URCU_TLS(rcu_reader)->ctr & RCU_GP_CTR_NEST_MASK;
+}
+
 #ifdef __cplusplus 
 }
 #endif
index f6e5580..ea5e13a 100644 (file)
@@ -190,6 +190,18 @@ static inline void _rcu_read_unlock(void)
 {
 }
 
+/*
+ * Returns whether within a RCU read-side critical section.
+ *
+ * This function is less than 10 lines long.  The intent is that this
+ * function meets the 10-line criterion for LGPL, allowing this function
+ * to be invoked directly from non-LGPL code.
+ */
+static inline int _rcu_read_ongoing(void)
+{
+       return URCU_TLS(rcu_reader).ctr;
+}
+
 /*
  * This is a helper function for _rcu_quiescent_state().
  * The first cmm_smp_mb() ensures memory accesses in the prior read-side
index 973826a..6c8b926 100644 (file)
@@ -329,6 +329,18 @@ static inline void _rcu_read_unlock(void)
        cmm_barrier();  /* Ensure the compiler does not reorder us with mutex */
 }
 
+/*
+ * Returns whether within a RCU read-side critical section.
+ *
+ * This function is less than 10 lines long.  The intent is that this
+ * function meets the 10-line criterion for LGPL, allowing this function
+ * to be invoked directly from non-LGPL code.
+ */
+static inline int _rcu_read_ongoing(void)
+{
+       return URCU_TLS(rcu_reader).ctr & RCU_GP_CTR_NEST_MASK;
+}
+
 #ifdef __cplusplus
 }
 #endif
This page took 0.051014 seconds and 4 git commands to generate.