X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=urcu%2Fstatic%2Furcu-bp.h;h=a2f73687d0a1995e5b3207b9f3fd3b970499d961;hb=a5a9f428a238e790d6c97299bc214b5cca815cd7;hp=64c32ea1ace5f14228e760f48383a47c03b8862d;hpb=bc2433a9853a945a825c244e9ccfe341b73b2ceb;p=urcu.git diff --git a/urcu/static/urcu-bp.h b/urcu/static/urcu-bp.h index 64c32ea..a2f7368 100644 --- a/urcu/static/urcu-bp.h +++ b/urcu/static/urcu-bp.h @@ -6,8 +6,8 @@ * * Userspace RCU header. * - * TO BE INCLUDED ONLY IN LGPL-COMPATIBLE CODE. See urcu.h for linking - * dynamically with the userspace rcu library. + * TO BE INCLUDED ONLY IN CODE THAT IS TO BE RECOMPILED ON EACH LIBURCU + * RELEASE. See urcu.h for linking dynamically with the userspace rcu library. * * Copyright (c) 2009 Mathieu Desnoyers * Copyright (c) 2009 Paul E. McKenney, IBM Corporation. @@ -38,6 +38,7 @@ #include #include #include +#include /* * This code section can only be included in LGPL 2.1 compatible source code. @@ -51,11 +52,6 @@ extern "C" { #endif -/* - * Active attempts to check for reader Q.S. before calling sleep(). - */ -#define RCU_QS_ACTIVE_ATTEMPTS 100 - #ifdef DEBUG_RCU #define rcu_assert(args...) assert(args) #else @@ -79,25 +75,25 @@ extern "C" { #define MAX_SLEEP 50 extern unsigned int yield_active; -extern unsigned int __thread rand_yield; +extern DECLARE_URCU_TLS(unsigned int, rand_yield); static inline void debug_yield_read(void) { if (yield_active & YIELD_READ) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); + if (rand_r(&URCU_TLS(rand_yield)) & 0x1) + usleep(rand_r(&URCU_TLS(rand_yield)) % MAX_SLEEP); } static inline void debug_yield_write(void) { if (yield_active & YIELD_WRITE) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); + if (rand_r(&URCU_TLS(rand_yield)) & 0x1) + usleep(rand_r(&URCU_TLS(rand_yield)) % MAX_SLEEP); } static inline void debug_yield_init(void) { - rand_yield = time(NULL) ^ pthread_self(); + URCU_TLS(rand_yield) = time(NULL) ^ pthread_self(); } #else static inline void debug_yield_read(void) @@ -149,7 +145,7 @@ struct rcu_reader { * Adds a pointer dereference on the read-side, but won't require to unregister * the reader thread. */ -extern struct rcu_reader __thread *rcu_reader; +extern DECLARE_URCU_TLS(struct rcu_reader *, rcu_reader); static inline int rcu_old_gp_ongoing(long *value) { @@ -166,39 +162,55 @@ static inline int rcu_old_gp_ongoing(long *value) ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); } +/* + * Helper for _rcu_read_lock(). The format of rcu_gp_ctr (as well as + * the per-thread rcu_reader.ctr) has the upper bits containing a count of + * _rcu_read_lock() nesting, and a lower-order bit that contains either zero + * or RCU_GP_CTR_PHASE. The smp_mb_slave() ensures that the accesses in + * _rcu_read_lock() happen before the subsequent read-side critical section. + */ +static inline void _rcu_read_lock_update(unsigned long tmp) +{ + if (caa_likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { + _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); + cmm_smp_mb(); + } else + _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, tmp + RCU_GP_COUNT); +} + +/* + * Enter an RCU read-side critical section. + * + * The first cmm_barrier() call ensures that the compiler does not reorder + * the body of _rcu_read_lock() with a mutex. + * + * This function and its helper are both less than 10 lines long. The + * intent is that this function meets the 10-line criterion in LGPL, + * allowing this function to be invoked directly from non-LGPL code. + */ static inline void _rcu_read_lock(void) { long tmp; - /* Check if registered */ - if (unlikely(!rcu_reader)) - rcu_bp_register(); - + if (caa_unlikely(!URCU_TLS(rcu_reader))) + rcu_bp_register(); /* If not yet registered. */ cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ - tmp = rcu_reader->ctr; - /* - * rcu_gp_ctr is - * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) - */ - if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { - _CMM_STORE_SHARED(rcu_reader->ctr, _CMM_LOAD_SHARED(rcu_gp_ctr)); - /* - * Set active readers count for outermost nesting level before - * accessing the pointer. - */ - cmm_smp_mb(); - } else { - _CMM_STORE_SHARED(rcu_reader->ctr, tmp + RCU_GP_COUNT); - } + tmp = URCU_TLS(rcu_reader)->ctr; + _rcu_read_lock_update(tmp); } +/* + * Exit an RCU read-side critical section. This function is less than + * 10 lines of code, and is intended to be usable by non-LGPL code, as + * called out in LGPL. + */ static inline void _rcu_read_unlock(void) { /* * Finish using rcu before decrementing the pointer. */ cmm_smp_mb(); - _CMM_STORE_SHARED(rcu_reader->ctr, rcu_reader->ctr - RCU_GP_COUNT); + _CMM_STORE_SHARED(URCU_TLS(rcu_reader)->ctr, URCU_TLS(rcu_reader)->ctr - RCU_GP_COUNT); cmm_barrier(); /* Ensure the compiler does not reorder us with mutex */ }