X-Git-Url: http://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fstatic%2Furcu-qsbr.h;h=ea5e13adebd5fae0374a5ad81693dd6cf46436c2;hp=c8a87b8d777a7ce0bcae127a5d1bd1545bfee561;hb=882f335739b978d1c55be2faeed077f315afe5d7;hpb=6ff854acfa013195bdb71dddc654ec76a4c296c9 diff --git a/urcu/static/urcu-qsbr.h b/urcu/static/urcu-qsbr.h index c8a87b8..ea5e13a 100644 --- a/urcu/static/urcu-qsbr.h +++ b/urcu/static/urcu-qsbr.h @@ -62,6 +62,12 @@ extern "C" { #define rcu_assert(args...) #endif +enum rcu_state { + RCU_READER_ACTIVE_CURRENT, + RCU_READER_ACTIVE_OLD, + RCU_READER_INACTIVE, +}; + #ifdef DEBUG_YIELD #include #include @@ -149,12 +155,16 @@ static inline void wake_up_gp(void) } } -static inline int rcu_gp_ongoing(unsigned long *ctr) +static inline enum rcu_state rcu_reader_state(unsigned long *ctr) { unsigned long v; v = CMM_LOAD_SHARED(*ctr); - return v && (v != rcu_gp_ctr); + if (!v) + return RCU_READER_INACTIVE; + if (v == rcu_gp_ctr) + return RCU_READER_ACTIVE_CURRENT; + return RCU_READER_ACTIVE_OLD; } /* @@ -181,21 +191,56 @@ static inline void _rcu_read_unlock(void) } /* - * Inform RCU of a quiescent state. + * 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 void _rcu_quiescent_state(void) +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 + * critical sections are not reordered with store to + * URCU_TLS(rcu_reader).ctr, and ensures that mutexes held within an + * offline section that would happen to end with this + * rcu_quiescent_state() call are not reordered with + * store to URCU_TLS(rcu_reader).ctr. + */ +static inline void _rcu_quiescent_state_update_and_wakeup(unsigned long gp_ctr) { cmm_smp_mb(); - _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); + _CMM_STORE_SHARED(URCU_TLS(rcu_reader).ctr, gp_ctr); cmm_smp_mb(); /* write URCU_TLS(rcu_reader).ctr before read futex */ wake_up_gp(); cmm_smp_mb(); } +/* + * Inform RCU of a quiescent state. + * + * 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. + * + * We skip the memory barriers and gp store if our local ctr already + * matches the global rcu_gp_ctr value: this is OK because a prior + * _rcu_quiescent_state() or _rcu_thread_online() already updated it + * within our thread, so we have no quiescent state to report. + */ +static inline void _rcu_quiescent_state(void) +{ + unsigned long gp_ctr; + + if ((gp_ctr = CMM_LOAD_SHARED(rcu_gp_ctr)) == URCU_TLS(rcu_reader).ctr) + return; + _rcu_quiescent_state_update_and_wakeup(gp_ctr); +} + /* * Take a thread offline, prohibiting it from entering further RCU * read-side critical sections.