X-Git-Url: http://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fstatic%2Furcu-qsbr.h;h=ea5e13adebd5fae0374a5ad81693dd6cf46436c2;hp=8b16a4abc4586783fd5a267126e43063050f58f6;hb=882f335739b978d1c55be2faeed077f315afe5d7;hpb=1de4df4b770e5e90440008becc5e14a15c75c6e0 diff --git a/urcu/static/urcu-qsbr.h b/urcu/static/urcu-qsbr.h index 8b16a4a..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 @@ -93,7 +99,7 @@ static inline void rcu_debug_yield_write(void) static inline void rcu_debug_yield_init(void) { - URCU_TLS(rcu_rand_yield) = time(NULL) ^ pthread_self(); + URCU_TLS(rcu_rand_yield) = time(NULL) ^ (unsigned long) pthread_self(); } #else static inline void rcu_debug_yield_read(void) @@ -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.