X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fstatic%2Furcu-bp.h;h=6187bd31b5325fb292057e95f7236285cb846019;hp=832ba0fe2b238293558761fa94b3bbdd9ba05e14;hb=1de4df4b770e5e90440008becc5e14a15c75c6e0;hpb=b7b6a8f52c051dca78161908670e3f51b9b33080 diff --git a/urcu/static/urcu-bp.h b/urcu/static/urcu-bp.h index 832ba0f..6187bd3 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. @@ -63,8 +64,8 @@ extern "C" { #include #include -#define YIELD_READ (1 << 0) -#define YIELD_WRITE (1 << 1) +#define RCU_YIELD_READ (1 << 0) +#define RCU_YIELD_WRITE (1 << 1) /* * Updates without RCU_MB are much slower. Account this in @@ -73,37 +74,37 @@ extern "C" { /* maximum sleep delay, in us */ #define MAX_SLEEP 50 -extern unsigned int yield_active; -extern unsigned int __thread rand_yield; +extern unsigned int rcu_yield_active; +extern DECLARE_URCU_TLS(unsigned int, rcu_rand_yield); -static inline void debug_yield_read(void) +static inline void rcu_debug_yield_read(void) { - if (yield_active & YIELD_READ) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); + if (rcu_yield_active & RCU_YIELD_READ) + if (rand_r(&URCU_TLS(rcu_rand_yield)) & 0x1) + usleep(rand_r(&URCU_TLS(rcu_rand_yield)) % MAX_SLEEP); } -static inline void debug_yield_write(void) +static inline void rcu_debug_yield_write(void) { - if (yield_active & YIELD_WRITE) - if (rand_r(&rand_yield) & 0x1) - usleep(rand_r(&rand_yield) % MAX_SLEEP); + if (rcu_yield_active & RCU_YIELD_WRITE) + if (rand_r(&URCU_TLS(rcu_rand_yield)) & 0x1) + usleep(rand_r(&URCU_TLS(rcu_rand_yield)) % MAX_SLEEP); } -static inline void debug_yield_init(void) +static inline void rcu_debug_yield_init(void) { - rand_yield = time(NULL) ^ pthread_self(); + URCU_TLS(rcu_rand_yield) = time(NULL) ^ pthread_self(); } #else -static inline void debug_yield_read(void) +static inline void rcu_debug_yield_read(void) { } -static inline void debug_yield_write(void) +static inline void rcu_debug_yield_write(void) { } -static inline void debug_yield_init(void) +static inline void rcu_debug_yield_init(void) { } @@ -144,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) { @@ -161,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 */ }