From: Mathieu Desnoyers Date: Tue, 30 Apr 2013 00:17:22 +0000 (-0400) Subject: Add rcu_read_ongoing() API to each urcu flavor X-Git-Tag: v0.8.0~95 X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=commitdiff_plain;h=882f335739b978d1c55be2faeed077f315afe5d7 Add rcu_read_ongoing() API to each urcu flavor 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 --- diff --git a/tests/test_urcu.c b/tests/test_urcu.c index 3c5c492..5059dde 100644 --- a/tests/test_urcu.c +++ b/tests/test_urcu.c @@ -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) diff --git a/tests/test_urcu_bp.c b/tests/test_urcu_bp.c index 8cb74ff..1926fbb 100644 --- a/tests/test_urcu_bp.c +++ b/tests/test_urcu_bp.c @@ -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) diff --git a/tests/test_urcu_qsbr.c b/tests/test_urcu_qsbr.c index 065557a..f98e273 100644 --- a/tests/test_urcu_qsbr.c +++ b/tests/test_urcu_qsbr.c @@ -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) diff --git a/urcu-bp.c b/urcu-bp.c index f99c0e5..8207a41 100644 --- 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. */ diff --git a/urcu-bp.h b/urcu-bp.h index 833688f..4718f3b 100644 --- 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) \ diff --git a/urcu-flavor.h b/urcu-flavor.h index 9af4d0e..c04f1db 100644 --- a/urcu-flavor.h +++ b/urcu-flavor.h @@ -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, \ diff --git a/urcu-qsbr.c b/urcu-qsbr.c index 3c2c65d..786a80d 100644 --- a/urcu-qsbr.c +++ b/urcu-qsbr.c @@ -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(); diff --git a/urcu-qsbr.h b/urcu-qsbr.h index a2f6575..bb0523c 100644 --- a/urcu-qsbr.h +++ b/urcu-qsbr.h @@ -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 --- 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 --- 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 */ diff --git a/urcu/map/urcu-bp.h b/urcu/map/urcu-bp.h index 63582fd..8c819a6 100644 --- a/urcu/map/urcu-bp.h +++ b/urcu/map/urcu-bp.h @@ -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 diff --git a/urcu/map/urcu-qsbr.h b/urcu/map/urcu-qsbr.h index f0aecc9..c40af35 100644 --- a/urcu/map/urcu-qsbr.h +++ b/urcu/map/urcu-qsbr.h @@ -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 diff --git a/urcu/map/urcu.h b/urcu/map/urcu.h index 759cb41..becc6a0 100644 --- a/urcu/map/urcu.h +++ b/urcu/map/urcu.h @@ -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 @@ -115,6 +117,8 @@ #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 @@ -158,6 +162,8 @@ #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 diff --git a/urcu/static/urcu-bp.h b/urcu/static/urcu-bp.h index c7f5326..2f36520 100644 --- a/urcu/static/urcu-bp.h +++ b/urcu/static/urcu-bp.h @@ -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 diff --git a/urcu/static/urcu-qsbr.h b/urcu/static/urcu-qsbr.h index f6e5580..ea5e13a 100644 --- a/urcu/static/urcu-qsbr.h +++ b/urcu/static/urcu-qsbr.h @@ -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 diff --git a/urcu/static/urcu.h b/urcu/static/urcu.h index 973826a..6c8b926 100644 --- a/urcu/static/urcu.h +++ b/urcu/static/urcu.h @@ -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