X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=urcu-qsbr-static.h;h=9cc5db493ca1362d1781b44507a10e562623df1f;hb=b3c4dd1a5c12b59efdee51be209767a9f406a715;hp=752d4b9aced8630a94fca3bcf1e6338b012d0e36;hpb=7ac06cef7a7d9394332837edc5c0e9595286a5fc;p=urcu.git diff --git a/urcu-qsbr-static.h b/urcu-qsbr-static.h index 752d4b9..9cc5db4 100644 --- a/urcu-qsbr-static.h +++ b/urcu-qsbr-static.h @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -96,11 +98,16 @@ /* * If a reader is really non-cooperative and refuses to commit its - * rcu_reader_qs_gp count to memory (there is no barrier in the reader + * rcu_reader qs_gp count to memory (there is no barrier in the reader * per-se), kick it after a few loops waiting for it. */ #define KICK_READER_LOOPS 10000 +/* + * Active attempts to check for reader Q.S. before calling sched_yield(). + */ +#define RCU_QS_ACTIVE_ATTEMPTS 100 + #ifdef DEBUG_RCU #define rcu_assert(args...) assert(args) #else @@ -160,26 +167,49 @@ static inline void reader_barrier() smp_mb(); } +#define RCU_GP_ONLINE (1UL << 0) +#define RCU_GP_ONGOING (1UL << 1) +#define RCU_GP_CTR (1UL << 2) + /* * Global quiescent period counter with low-order bits unused. * Using a int rather than a char to eliminate false register dependencies * causing stalls on some architectures. */ -extern long urcu_gp_ctr; +extern unsigned long urcu_gp_ctr; -extern long __thread rcu_reader_qs_gp; +struct urcu_reader_status { + unsigned long qs_gp; + unsigned long gp_waiting; +}; -static inline int rcu_gp_ongoing(long *value) +extern struct urcu_reader_status __thread urcu_reader_status; + +#if (BITS_PER_LONG < 64) +static inline int rcu_gp_ongoing(unsigned long *value) { + unsigned long reader_gp; + if (value == NULL) return 0; + reader_gp = LOAD_SHARED(*value); + return reader_gp && ((reader_gp ^ urcu_gp_ctr) & RCU_GP_CTR); +} +#else /* !(BITS_PER_LONG < 64) */ +static inline int rcu_gp_ongoing(unsigned long *value) +{ + unsigned long reader_gp; - return LOAD_SHARED(*value) & 1; + if (value == NULL) + return 0; + reader_gp = LOAD_SHARED(*value); + return reader_gp && (reader_gp - urcu_gp_ctr > ULONG_MAX / 2); } +#endif /* !(BITS_PER_LONG < 64) */ static inline void _rcu_read_lock(void) { - rcu_assert(rcu_reader_qs_gp & 1); + rcu_assert(urcu_reader_status.qs_gp); } static inline void _rcu_read_unlock(void) @@ -188,20 +218,36 @@ static inline void _rcu_read_unlock(void) static inline void _rcu_quiescent_state(void) { - smp_mb(); - rcu_reader_qs_gp = ACCESS_ONCE(urcu_gp_ctr) + 1; + long gp_ctr; + + smp_mb(); + /* + * volatile accesses can be reordered by the compiler when put in the + * same expression. + */ + if (unlikely((gp_ctr = LOAD_SHARED(urcu_gp_ctr)) & RCU_GP_ONGOING) && + unlikely(urcu_reader_status.gp_waiting)) { + _STORE_SHARED(urcu_reader_status.qs_gp, gp_ctr); + sched_yield(); + } else { + _STORE_SHARED(urcu_reader_status.qs_gp, gp_ctr); + } smp_mb(); } static inline void _rcu_thread_offline(void) { smp_mb(); - rcu_reader_qs_gp = ACCESS_ONCE(urcu_gp_ctr); + STORE_SHARED(urcu_reader_status.qs_gp, 0); + if (unlikely(LOAD_SHARED(urcu_gp_ctr) & RCU_GP_ONGOING) && + unlikely(urcu_reader_status.gp_waiting)) { + sched_yield(); + } } static inline void _rcu_thread_online(void) { - rcu_reader_qs_gp = ACCESS_ONCE(urcu_gp_ctr) + 1; + _STORE_SHARED(urcu_reader_status.qs_gp, LOAD_SHARED(urcu_gp_ctr)); smp_mb(); } @@ -226,6 +272,22 @@ static inline void _rcu_thread_online(void) STORE_SHARED(p, v); \ }) +/** + * _rcu_cmpxchg_pointer - same as rcu_assign_pointer, but tests if the pointer + * is as expected by "old". If succeeds, returns the previous pointer to the + * data structure, which can be safely freed after waiting for a quiescent state + * using synchronize_rcu(). If fails (unexpected value), returns old (which + * should not be freed !). + */ + +#define _rcu_cmpxchg_pointer(p, old, _new) \ + ({ \ + if (!__builtin_constant_p(_new) || \ + ((_new) != NULL)) \ + wmb(); \ + cmpxchg(p, old, _new); \ + }) + /** * _rcu_xchg_pointer - same as rcu_assign_pointer, but returns the previous * pointer to the data structure, which can be safely freed after waiting for a