| uatomic_arch.h | | uatomic_arch.h | |
| | | | |
| skipping to change at line 408 | | skipping to change at line 408 | |
| #endif | | #endif | |
| } | | } | |
| /* generate an illegal instruction. Cannot catch this with linker tr
icks | | /* generate an illegal instruction. Cannot catch this with linker tr
icks | |
| * when optimizations are disabled. */ | | * when optimizations are disabled. */ | |
| __asm__ __volatile__("ud2"); | | __asm__ __volatile__("ud2"); | |
| return; | | return; | |
| } | | } | |
| | | | |
| #define _uatomic_dec(addr) (__uatomic_dec((addr), sizeof(*(addr)))) | | #define _uatomic_dec(addr) (__uatomic_dec((addr), sizeof(*(addr)))) | |
| | | | |
|
| #if ((BITS_PER_LONG != 64) && defined(CONFIG_URCU_COMPAT_ARCH)) | | #if ((BITS_PER_LONG != 64) && defined(CONFIG_RCU_COMPAT_ARCH)) | |
| extern int __urcu_cas_avail; | | extern int __rcu_cas_avail; | |
| extern int __urcu_cas_init(void); | | extern int __rcu_cas_init(void); | |
| | | | |
| #define UATOMIC_COMPAT(insn)
\ | | #define UATOMIC_COMPAT(insn)
\ | |
|
| ((likely(__urcu_cas_avail > 0))
\ | | ((likely(__rcu_cas_avail > 0))
\ | |
| ? (_uatomic_##insn)
\ | | ? (_uatomic_##insn)
\ | |
|
| : ((unlikely(__urcu_cas_avail < 0) | | : ((unlikely(__rcu_cas_avail < 0) | |
| \ | | \ | |
| ? ((__urcu_cas_init() > 0) | | ? ((__rcu_cas_init() > 0) | |
| \ | | \ | |
| ? (_uatomic_##insn)
\ | | ? (_uatomic_##insn)
\ | |
| : (compat_uatomic_##insn))
\ | | : (compat_uatomic_##insn))
\ | |
| : (compat_uatomic_##insn)))) | | : (compat_uatomic_##insn)))) | |
| | | | |
| extern unsigned long _compat_uatomic_set(void *addr, | | extern unsigned long _compat_uatomic_set(void *addr, | |
| unsigned long _new, int len); | | unsigned long _new, int len); | |
| #define compat_uatomic_set(addr, _new)
\ | | #define compat_uatomic_set(addr, _new)
\ | |
| ((__typeof__(*(addr))) _compat_uatomic_set((addr),
\ | | ((__typeof__(*(addr))) _compat_uatomic_set((addr),
\ | |
| (unsigned long)(_new),
\ | | (unsigned long)(_new),
\ | |
| sizeof(*(addr)))) | | sizeof(*(addr)))) | |
| | | | |
End of changes. 3 change blocks. |
| 8 lines changed or deleted | | 8 lines changed or added | |
|
| urcu-bp-static.h | | urcu-bp-static.h | |
| | | | |
| skipping to change at line 76 | | skipping to change at line 76 | |
| #ifdef DEBUG_YIELD | | #ifdef DEBUG_YIELD | |
| #include <sched.h> | | #include <sched.h> | |
| #include <time.h> | | #include <time.h> | |
| #include <pthread.h> | | #include <pthread.h> | |
| #include <unistd.h> | | #include <unistd.h> | |
| | | | |
| #define YIELD_READ (1 << 0) | | #define YIELD_READ (1 << 0) | |
| #define YIELD_WRITE (1 << 1) | | #define YIELD_WRITE (1 << 1) | |
| | | | |
| /* | | /* | |
|
| * Updates without URCU_MB are much slower. Account this in | | * Updates without RCU_MB are much slower. Account this in | |
| * the delay. | | * the delay. | |
| */ | | */ | |
| /* maximum sleep delay, in us */ | | /* maximum sleep delay, in us */ | |
| #define MAX_SLEEP 50 | | #define MAX_SLEEP 50 | |
| | | | |
| extern unsigned int yield_active; | | extern unsigned int yield_active; | |
| extern unsigned int __thread rand_yield; | | extern unsigned int __thread rand_yield; | |
| | | | |
| static inline void debug_yield_read(void) | | static inline void debug_yield_read(void) | |
| { | | { | |
| | | | |
| skipping to change at line 119 | | skipping to change at line 119 | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void debug_yield_init(void) | | static inline void debug_yield_init(void) | |
| { | | { | |
| | | | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| /* | | /* | |
|
| * The trick here is that RCU_GP_CTR_BIT must be a multiple of 8 so we can
use a | | * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we ca
n use a | |
| * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | | * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | |
| */ | | */ | |
| #define RCU_GP_COUNT (1UL << 0) | | #define RCU_GP_COUNT (1UL << 0) | |
| /* Use the amount of bits equal to half of the architecture long size */ | | /* Use the amount of bits equal to half of the architecture long size */ | |
|
| #define RCU_GP_CTR_BIT (1UL << (sizeof(long) << 2)) | | #define RCU_GP_CTR_PHASE (1UL << (sizeof(long) << 2)) | |
| #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BIT - 1) | | #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_PHASE - 1) | |
| | | | |
| /* | | /* | |
| * Used internally by _rcu_read_lock. | | * Used internally by _rcu_read_lock. | |
| */ | | */ | |
| extern void rcu_bp_register(void); | | extern void rcu_bp_register(void); | |
| | | | |
| /* | | /* | |
| * Global quiescent period counter with low-order bits unused. | | * Global quiescent period counter with low-order bits unused. | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
|
| extern long urcu_gp_ctr; | | extern long rcu_gp_ctr; | |
| | | | |
|
| struct urcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| long ctr; | | long ctr; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
| struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | | struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | |
| pthread_t tid; | | pthread_t tid; | |
| int alloc; /* registry entry allocated */ | | int alloc; /* registry entry allocated */ | |
| }; | | }; | |
| | | | |
| /* | | /* | |
| * Bulletproof version keeps a pointer to a registry not part of the TLS. | | * Bulletproof version keeps a pointer to a registry not part of the TLS. | |
| * Adds a pointer dereference on the read-side, but won't require to unregi
ster | | * Adds a pointer dereference on the read-side, but won't require to unregi
ster | |
| * the reader thread. | | * the reader thread. | |
| */ | | */ | |
|
| extern struct urcu_reader __thread *urcu_reader; | | extern struct rcu_reader __thread *rcu_reader; | |
| | | | |
| static inline int rcu_old_gp_ongoing(long *value) | | static inline int rcu_old_gp_ongoing(long *value) | |
| { | | { | |
| long v; | | long v; | |
| | | | |
| if (value == NULL) | | if (value == NULL) | |
| return 0; | | return 0; | |
| /* | | /* | |
| * Make sure both tests below are done on the same version of *value | | * Make sure both tests below are done on the same version of *value | |
| * to insure consistency. | | * to insure consistency. | |
| */ | | */ | |
| v = LOAD_SHARED(*value); | | v = LOAD_SHARED(*value); | |
| return (v & RCU_GP_CTR_NEST_MASK) && | | return (v & RCU_GP_CTR_NEST_MASK) && | |
|
| ((v ^ urcu_gp_ctr) & RCU_GP_CTR_BIT); | | ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
| long tmp; | | long tmp; | |
| | | | |
| /* Check if registered */ | | /* Check if registered */ | |
|
| if (unlikely(!urcu_reader)) | | if (unlikely(!rcu_reader)) | |
| rcu_bp_register(); | | rcu_bp_register(); | |
| | | | |
|
| tmp = urcu_reader->ctr; | | tmp = rcu_reader->ctr; | |
| /* urcu_gp_ctr = RCU_GP_COUNT | (~RCU_GP_CTR_BIT or RCU_GP_CTR_BIT) | | /* | |
| */ | | * rcu_gp_ctr is | |
| | | * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | |
| | | */ | |
| if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | | if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | |
|
| _STORE_SHARED(urcu_reader->ctr, _LOAD_SHARED(urcu_gp_ctr)); | | _STORE_SHARED(rcu_reader->ctr, _LOAD_SHARED(rcu_gp_ctr)); | |
| /* | | /* | |
| * Set active readers count for outermost nesting level befo
re | | * Set active readers count for outermost nesting level befo
re | |
| * accessing the pointer. | | * accessing the pointer. | |
| */ | | */ | |
| smp_mb(); | | smp_mb(); | |
| } else { | | } else { | |
|
| _STORE_SHARED(urcu_reader->ctr, tmp + RCU_GP_COUNT); | | _STORE_SHARED(rcu_reader->ctr, tmp + RCU_GP_COUNT); | |
| } | | } | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| /* | | /* | |
| * Finish using rcu before decrementing the pointer. | | * Finish using rcu before decrementing the pointer. | |
| */ | | */ | |
| smp_mb(); | | smp_mb(); | |
|
| _STORE_SHARED(urcu_reader->ctr, urcu_reader->ctr - RCU_GP_COUNT); | | _STORE_SHARED(rcu_reader->ctr, rcu_reader->ctr - RCU_GP_COUNT); | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_BP_STATIC_H */ | | #endif /* _URCU_BP_STATIC_H */ | |
| | | | |
End of changes. 12 change blocks. |
| 15 lines changed or deleted | | 17 lines changed or added | |
|
| urcu-defer-static.h | | urcu-defer-static.h | |
| | | | |
| skipping to change at line 39 | | skipping to change at line 39 | |
| * IBM's contributions to this file may be relicensed under LGPLv2 or later
. | | * IBM's contributions to this file may be relicensed under LGPLv2 or later
. | |
| */ | | */ | |
| | | | |
| #include <stdlib.h> | | #include <stdlib.h> | |
| #include <pthread.h> | | #include <pthread.h> | |
| | | | |
| #include <urcu/compiler.h> | | #include <urcu/compiler.h> | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| #include <urcu/uatomic_arch.h> | | #include <urcu/uatomic_arch.h> | |
| #include <urcu/list.h> | | #include <urcu/list.h> | |
|
| | | #include <urcu/system.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
| /* | | /* | |
| * Number of entries in the per-thread defer queue. Must be power of 2. | | * Number of entries in the per-thread defer queue. Must be power of 2. | |
| */ | | */ | |
| #define DEFER_QUEUE_SIZE (1 << 12) | | #define DEFER_QUEUE_SIZE (1 << 12) | |
| #define DEFER_QUEUE_MASK (DEFER_QUEUE_SIZE - 1) | | #define DEFER_QUEUE_MASK (DEFER_QUEUE_SIZE - 1) | |
| | | | |
| skipping to change at line 68 | | skipping to change at line 69 | |
| */ | | */ | |
| #define DQ_FCT_BIT (1 << 0) | | #define DQ_FCT_BIT (1 << 0) | |
| #define DQ_IS_FCT_BIT(x) ((unsigned long)(x) & DQ_FCT_BIT) | | #define DQ_IS_FCT_BIT(x) ((unsigned long)(x) & DQ_FCT_BIT) | |
| #define DQ_SET_FCT_BIT(x) \ | | #define DQ_SET_FCT_BIT(x) \ | |
| (x = (void *)((unsigned long)(x) | DQ_FCT_BIT)) | | (x = (void *)((unsigned long)(x) | DQ_FCT_BIT)) | |
| #define DQ_CLEAR_FCT_BIT(x) \ | | #define DQ_CLEAR_FCT_BIT(x) \ | |
| (x = (void *)((unsigned long)(x) & ~DQ_FCT_BIT)) | | (x = (void *)((unsigned long)(x) & ~DQ_FCT_BIT)) | |
| #define DQ_FCT_MARK ((void *)(~DQ_FCT_BIT)) | | #define DQ_FCT_MARK ((void *)(~DQ_FCT_BIT)) | |
| | | | |
| /* | | /* | |
|
| * Identify a shared load. A smp_rmc() or smp_mc() should come before the l | | | |
| oad. | | | |
| */ | | | |
| #define _LOAD_SHARED(p) ACCESS_ONCE(p) | | | |
| | | | |
| /* | | | |
| * Load a data from shared memory, doing a cache flush if required. | | | |
| */ | | | |
| #define LOAD_SHARED(p) \ | | | |
| ({ \ | | | |
| smp_rmc(); \ | | | |
| _LOAD_SHARED(p); \ | | | |
| }) | | | |
| | | | |
| /* | | | |
| * Identify a shared store. A smp_wmc() or smp_mc() should follow the store | | | |
| . | | | |
| */ | | | |
| #define _STORE_SHARED(x, v) ({ ACCESS_ONCE(x) = (v); }) | | | |
| | | | |
| /* | | | |
| * Store v into x, where x is located in shared memory. Performs the requir | | | |
| ed | | | |
| * cache flush after writing. Returns v. | | | |
| */ | | | |
| #define STORE_SHARED(x, v) \ | | | |
| ({ \ | | | |
| _STORE_SHARED(x, v); \ | | | |
| smp_wmc(); \ | | | |
| (v); \ | | | |
| }) | | | |
| | | | |
| /* | | | |
| * This code section can only be included in LGPL 2.1 compatible source cod
e. | | * This code section can only be included in LGPL 2.1 compatible source cod
e. | |
| * See below for the function call wrappers which can be used in code meant
to | | * See below for the function call wrappers which can be used in code meant
to | |
| * be only linked with the Userspace RCU library. This comes with a small | | * be only linked with the Userspace RCU library. This comes with a small | |
| * performance degradation on the read-side due to the added function calls
. | | * performance degradation on the read-side due to the added function calls
. | |
| * This is required to permit relinking with newer versions of the library. | | * This is required to permit relinking with newer versions of the library. | |
| */ | | */ | |
| | | | |
| #ifdef DEBUG_RCU | | #ifdef DEBUG_RCU | |
| #define rcu_assert(args...) assert(args) | | #define rcu_assert(args...) assert(args) | |
| #else | | #else | |
| | | | |
End of changes. 2 change blocks. |
| 33 lines changed or deleted | | 1 lines changed or added | |
|
| urcu-futex.h | | urcu-futex.h | |
| | | | |
| skipping to change at line 44 | | skipping to change at line 44 | |
| * sys_futex compatibility header. | | * sys_futex compatibility header. | |
| * Use *only* *either of* futex_noasync OR futex_async on a given address. | | * Use *only* *either of* futex_noasync OR futex_async on a given address. | |
| * | | * | |
| * futex_noasync cannot be executed in signal handlers, but ensures that | | * futex_noasync cannot be executed in signal handlers, but ensures that | |
| * it will be put in a wait queue even in compatibility mode. | | * it will be put in a wait queue even in compatibility mode. | |
| * | | * | |
| * futex_async is signal-handler safe for the wakeup. It uses polling | | * futex_async is signal-handler safe for the wakeup. It uses polling | |
| * on the wait-side in compatibility mode. | | * on the wait-side in compatibility mode. | |
| */ | | */ | |
| | | | |
|
| #ifdef CONFIG_URCU_HAVE_FUTEX | | #ifdef CONFIG_RCU_HAVE_FUTEX | |
| #include <sys/syscall.h> | | #include <sys/syscall.h> | |
| #define futex(...) syscall(__NR_futex, __VA_ARGS__) | | #define futex(...) syscall(__NR_futex, __VA_ARGS__) | |
| #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ | | #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ | |
| futex(uaddr, op, val, timeout, uaddr2, val3) | | futex(uaddr, op, val, timeout, uaddr2, val3) | |
| #define futex_async(uaddr, op, val, timeout, uaddr2, val3) \ | | #define futex_async(uaddr, op, val, timeout, uaddr2, val3) \ | |
| futex(uaddr, op, val, timeout, uaddr2, val3) | | futex(uaddr, op, val, timeout, uaddr2, val3) | |
| #else | | #else | |
| extern int compat_futex_noasync(int *uaddr, int op, int val, | | extern int compat_futex_noasync(int *uaddr, int op, int val, | |
| const struct timespec *timeout, int *uaddr2, int val3); | | const struct timespec *timeout, int *uaddr2, int val3); | |
| #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ | | #define futex_noasync(uaddr, op, val, timeout, uaddr2, val3) \ | |
| | | | |
End of changes. 1 change blocks. |
| 1 lines changed or deleted | | 1 lines changed or added | |
|
| urcu-qsbr-static.h | | urcu-qsbr-static.h | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 60 | |
| /* | | /* | |
| * This code section can only be included in LGPL 2.1 compatible source cod
e. | | * This code section can only be included in LGPL 2.1 compatible source cod
e. | |
| * See below for the function call wrappers which can be used in code meant
to | | * See below for the function call wrappers which can be used in code meant
to | |
| * be only linked with the Userspace RCU library. This comes with a small | | * be only linked with the Userspace RCU library. This comes with a small | |
| * performance degradation on the read-side due to the added function calls
. | | * performance degradation on the read-side due to the added function calls
. | |
| * This is required to permit relinking with newer versions of the library. | | * This is required to permit relinking with newer versions of the library. | |
| */ | | */ | |
| | | | |
| /* | | /* | |
| * If a reader is really non-cooperative and refuses to commit its | | * If a reader is really non-cooperative and refuses to commit its | |
|
| * urcu_reader.ctr count to memory (there is no barrier in the reader | | * rcu_reader.ctr count to memory (there is no barrier in the reader | |
| * per-se), kick it after a few loops waiting for it. | | * per-se), kick it after a few loops waiting for it. | |
| */ | | */ | |
| #define KICK_READER_LOOPS 10000 | | #define KICK_READER_LOOPS 10000 | |
| | | | |
| /* | | /* | |
| * Active attempts to check for reader Q.S. before calling futex(). | | * Active attempts to check for reader Q.S. before calling futex(). | |
| */ | | */ | |
| #define RCU_QS_ACTIVE_ATTEMPTS 100 | | #define RCU_QS_ACTIVE_ATTEMPTS 100 | |
| | | | |
| #ifdef DEBUG_RCU | | #ifdef DEBUG_RCU | |
| | | | |
| skipping to change at line 124 | | skipping to change at line 124 | |
| static inline void debug_yield_write(void) | | static inline void debug_yield_write(void) | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void debug_yield_init(void) | | static inline void debug_yield_init(void) | |
| { | | { | |
| | | | |
| } | | } | |
| #endif | | #endif | |
| | | | |
|
| static inline void reader_barrier() | | | |
| { | | | |
| smp_mb(); | | | |
| } | | | |
| | | | |
| #define RCU_GP_ONLINE (1UL << 0) | | #define RCU_GP_ONLINE (1UL << 0) | |
| #define RCU_GP_CTR (1UL << 1) | | #define RCU_GP_CTR (1UL << 1) | |
| | | | |
| /* | | /* | |
| * Global quiescent period counter with low-order bits unused. | | * Global quiescent period counter with low-order bits unused. | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
|
| extern unsigned long urcu_gp_ctr; | | extern unsigned long rcu_gp_ctr; | |
| | | | |
|
| struct urcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| unsigned long ctr; | | unsigned long ctr; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
| struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | | struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | |
| pthread_t tid; | | pthread_t tid; | |
| }; | | }; | |
| | | | |
|
| extern struct urcu_reader __thread urcu_reader; | | extern struct rcu_reader __thread rcu_reader; | |
| | | | |
| extern int gp_futex; | | extern int gp_futex; | |
| | | | |
| /* | | /* | |
| * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | | * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | |
| */ | | */ | |
| static inline void wake_up_gp(void) | | static inline void wake_up_gp(void) | |
| { | | { | |
| if (unlikely(uatomic_read(&gp_futex) == -1)) { | | if (unlikely(uatomic_read(&gp_futex) == -1)) { | |
| uatomic_set(&gp_futex, 0); | | uatomic_set(&gp_futex, 0); | |
| | | | |
| skipping to change at line 171 | | skipping to change at line 166 | |
| } | | } | |
| | | | |
| #if (BITS_PER_LONG < 64) | | #if (BITS_PER_LONG < 64) | |
| static inline int rcu_gp_ongoing(unsigned long *value) | | static inline int rcu_gp_ongoing(unsigned long *value) | |
| { | | { | |
| unsigned long reader_gp; | | unsigned long reader_gp; | |
| | | | |
| if (value == NULL) | | if (value == NULL) | |
| return 0; | | return 0; | |
| reader_gp = LOAD_SHARED(*value); | | reader_gp = LOAD_SHARED(*value); | |
|
| return reader_gp && ((reader_gp ^ urcu_gp_ctr) & RCU_GP_CTR); | | return reader_gp && ((reader_gp ^ rcu_gp_ctr) & RCU_GP_CTR); | |
| } | | } | |
| #else /* !(BITS_PER_LONG < 64) */ | | #else /* !(BITS_PER_LONG < 64) */ | |
| static inline int rcu_gp_ongoing(unsigned long *value) | | static inline int rcu_gp_ongoing(unsigned long *value) | |
| { | | { | |
| unsigned long reader_gp; | | unsigned long reader_gp; | |
| | | | |
| if (value == NULL) | | if (value == NULL) | |
| return 0; | | return 0; | |
| reader_gp = LOAD_SHARED(*value); | | reader_gp = LOAD_SHARED(*value); | |
|
| return reader_gp && (reader_gp - urcu_gp_ctr > ULONG_MAX / 2); | | return reader_gp && (reader_gp - rcu_gp_ctr > ULONG_MAX / 2); | |
| } | | } | |
| #endif /* !(BITS_PER_LONG < 64) */ | | #endif /* !(BITS_PER_LONG < 64) */ | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
|
| rcu_assert(urcu_reader.ctr); | | rcu_assert(rcu_reader.ctr); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void _rcu_quiescent_state(void) | | static inline void _rcu_quiescent_state(void) | |
| { | | { | |
| smp_mb(); | | smp_mb(); | |
|
| _STORE_SHARED(urcu_reader.ctr, _LOAD_SHARED(urcu_gp_ctr)); | | _STORE_SHARED(rcu_reader.ctr, _LOAD_SHARED(rcu_gp_ctr)); | |
| smp_mb(); /* write urcu_reader.ctr before read futex */ | | smp_mb(); /* write rcu_reader.ctr before read futex */ | |
| wake_up_gp(); | | wake_up_gp(); | |
| smp_mb(); | | smp_mb(); | |
| } | | } | |
| | | | |
| static inline void _rcu_thread_offline(void) | | static inline void _rcu_thread_offline(void) | |
| { | | { | |
| smp_mb(); | | smp_mb(); | |
|
| STORE_SHARED(urcu_reader.ctr, 0); | | STORE_SHARED(rcu_reader.ctr, 0); | |
| smp_mb(); /* write urcu_reader.ctr before read futex */ | | smp_mb(); /* write rcu_reader.ctr before read futex */ | |
| wake_up_gp(); | | wake_up_gp(); | |
| } | | } | |
| | | | |
| static inline void _rcu_thread_online(void) | | static inline void _rcu_thread_online(void) | |
| { | | { | |
|
| _STORE_SHARED(urcu_reader.ctr, LOAD_SHARED(urcu_gp_ctr)); | | _STORE_SHARED(rcu_reader.ctr, LOAD_SHARED(rcu_gp_ctr)); | |
| smp_mb(); | | smp_mb(); | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_QSBR_STATIC_H */ | | #endif /* _URCU_QSBR_STATIC_H */ | |
| | | | |
End of changes. 11 change blocks. |
| 17 lines changed or deleted | | 12 lines changed or added | |
|
| urcu-qsbr.h | | urcu-qsbr.h | |
| | | | |
| skipping to change at line 65 | | skipping to change at line 65 | |
| /* | | /* | |
| * Mappings for static use of the userspace RCU library. | | * Mappings for static use of the userspace RCU library. | |
| * Should only be used in LGPL-compatible code. | | * Should only be used in LGPL-compatible code. | |
| */ | | */ | |
| | | | |
| /* | | /* | |
| * rcu_read_lock() | | * rcu_read_lock() | |
| * rcu_read_unlock() | | * rcu_read_unlock() | |
| * | | * | |
| * Mark the beginning and end of a read-side critical section. | | * Mark the beginning and end of a read-side critical section. | |
|
| * DON'T FORGET TO USE RCU_REGISTER/UNREGISTER_THREAD() FOR EACH THREAD WIT | | * DON'T FORGET TO USE rcu_register_thread/rcu_unregister_thread() FOR EACH | |
| H | | * THREAD WITH READ-SIDE CRITICAL SECTION. | |
| * READ-SIDE CRITICAL SECTION. | | | |
| */ | | */ | |
| #define rcu_read_lock() _rcu_read_lock() | | #define rcu_read_lock() _rcu_read_lock() | |
| #define rcu_read_unlock() _rcu_read_unlock() | | #define rcu_read_unlock() _rcu_read_unlock() | |
| | | | |
| #define rcu_quiescent_state() _rcu_quiescent_state() | | #define rcu_quiescent_state() _rcu_quiescent_state() | |
| #define rcu_thread_offline() _rcu_thread_offline() | | #define rcu_thread_offline() _rcu_thread_offline() | |
| #define rcu_thread_online() _rcu_thread_online() | | #define rcu_thread_online() _rcu_thread_online() | |
| | | | |
| #else /* !_LGPL_SOURCE */ | | #else /* !_LGPL_SOURCE */ | |
| | | | |
| /* | | /* | |
| * library wrappers to be used by non-LGPL compatible source code. | | * library wrappers to be used by non-LGPL compatible source code. | |
| */ | | */ | |
| | | | |
| /* | | /* | |
| * QSBR read lock/unlock are guaranteed to be no-ops. Therefore, we expose
them | | * QSBR read lock/unlock are guaranteed to be no-ops. Therefore, we expose
them | |
| * in the LGPL header for any code to use. However, the debug version is no
t | | * in the LGPL header for any code to use. However, the debug version is no
t | |
| * nops and may contain sanity checks. To activate it, applications must be | | * nops and may contain sanity checks. To activate it, applications must be | |
|
| * recompiled with -DURCU_DEBUG (even non-LGPL/GPL applications). This is t
he | | * recompiled with -DRCU_DEBUG (even non-LGPL/GPL applications). This is th
e | |
| * best trade-off between license/performance/code triviality and | | * best trade-off between license/performance/code triviality and | |
| * library debugging & tracing features we could come up with. | | * library debugging & tracing features we could come up with. | |
| */ | | */ | |
| | | | |
|
| #if (!defined(BUILD_QSBR_LIB) && defined(URCU_DEBUG)) | | #if (!defined(BUILD_QSBR_LIB) && defined(RCU_DEBUG)) | |
| | | | |
| static inline void rcu_read_lock(void) | | static inline void rcu_read_lock(void) | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void rcu_read_lock(void) | | static inline void rcu_read_lock(void) | |
| { | | { | |
| } | | } | |
| | | | |
|
| #else /* !URCU_DEBUG */ | | #else /* !RCU_DEBUG */ | |
| | | | |
| extern void rcu_read_lock(void); | | extern void rcu_read_lock(void); | |
| extern void rcu_read_unlock(void); | | extern void rcu_read_unlock(void); | |
| | | | |
|
| #endif /* !URCU_DEBUG */ | | #endif /* !RCU_DEBUG */ | |
| | | | |
| extern void rcu_quiescent_state(void); | | extern void rcu_quiescent_state(void); | |
| extern void rcu_thread_offline(void); | | extern void rcu_thread_offline(void); | |
| extern void rcu_thread_online(void); | | extern void rcu_thread_online(void); | |
| | | | |
| #endif /* !_LGPL_SOURCE */ | | #endif /* !_LGPL_SOURCE */ | |
| | | | |
| extern void synchronize_rcu(void); | | extern void synchronize_rcu(void); | |
| | | | |
| /* | | /* | |
| | | | |
End of changes. 5 change blocks. |
| 7 lines changed or deleted | | 6 lines changed or added | |
|
| urcu-static.h | | urcu-static.h | |
| | | | |
| skipping to change at line 48 | | skipping to change at line 48 | |
| #include <urcu/arch.h> | | #include <urcu/arch.h> | |
| #include <urcu/system.h> | | #include <urcu/system.h> | |
| #include <urcu/uatomic_arch.h> | | #include <urcu/uatomic_arch.h> | |
| #include <urcu/list.h> | | #include <urcu/list.h> | |
| #include <urcu/urcu-futex.h> | | #include <urcu/urcu-futex.h> | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| extern "C" { | | extern "C" { | |
| #endif | | #endif | |
| | | | |
|
| | | /* Default is RCU_MEMBARRIER */ | |
| | | #if !defined(RCU_MEMBARRIER) && !defined(RCU_MB) && !defined(RCU_SIGNAL) | |
| | | #define RCU_MEMBARRIER | |
| | | #endif | |
| | | | |
| | | #ifdef RCU_MEMBARRIER | |
| | | #include <unistd.h> | |
| | | #include <sys/syscall.h> | |
| | | | |
| | | /* If the headers do not support SYS_membarrier, statically use RCU_MB */ | |
| | | #ifdef SYS_membarrier | |
| | | # define MEMBARRIER_EXPEDITED (1 << 0) | |
| | | # define MEMBARRIER_DELAYED (1 << 1) | |
| | | # define MEMBARRIER_QUERY (1 << 16) | |
| | | # define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__ | |
| | | ) | |
| | | #else | |
| | | # undef RCU_MEMBARRIER | |
| | | # define RCU_MB | |
| | | #endif | |
| | | #endif | |
| | | | |
| /* | | /* | |
| * This code section can only be included in LGPL 2.1 compatible source cod
e. | | * This code section can only be included in LGPL 2.1 compatible source cod
e. | |
| * See below for the function call wrappers which can be used in code meant
to | | * See below for the function call wrappers which can be used in code meant
to | |
| * be only linked with the Userspace RCU library. This comes with a small | | * be only linked with the Userspace RCU library. This comes with a small | |
| * performance degradation on the read-side due to the added function calls
. | | * performance degradation on the read-side due to the added function calls
. | |
| * This is required to permit relinking with newer versions of the library. | | * This is required to permit relinking with newer versions of the library. | |
| */ | | */ | |
| | | | |
| /* | | /* | |
| * The signal number used by the RCU library can be overridden with | | * The signal number used by the RCU library can be overridden with | |
|
| * -DSIGURCU= when compiling the library. | | * -DSIGRCU= when compiling the library. | |
| | | * Provide backward compatibility for liburcu 0.3.x SIGURCU. | |
| */ | | */ | |
|
| #ifndef SIGURCU | | #ifdef SIGURCU | |
| #define SIGURCU SIGUSR1 | | #define SIGRCU SIGURCU | |
| | | #endif | |
| | | | |
| | | #ifndef SIGRCU | |
| | | #define SIGRCU SIGUSR1 | |
| #endif | | #endif | |
| | | | |
| /* | | /* | |
| * If a reader is really non-cooperative and refuses to commit its | | * If a reader is really non-cooperative and refuses to commit its | |
|
| * urcu_active_readers count to memory (there is no barrier in the reader | | * rcu_active_readers count to memory (there is no barrier in the reader | |
| * per-se), kick it after a few loops waiting for it. | | * per-se), kick it after a few loops waiting for it. | |
| */ | | */ | |
| #define KICK_READER_LOOPS 10000 | | #define KICK_READER_LOOPS 10000 | |
| | | | |
| /* | | /* | |
| * Active attempts to check for reader Q.S. before calling futex(). | | * Active attempts to check for reader Q.S. before calling futex(). | |
| */ | | */ | |
| #define RCU_QS_ACTIVE_ATTEMPTS 100 | | #define RCU_QS_ACTIVE_ATTEMPTS 100 | |
| | | | |
| #ifdef DEBUG_RCU | | #ifdef DEBUG_RCU | |
| | | | |
| skipping to change at line 92 | | skipping to change at line 118 | |
| #ifdef DEBUG_YIELD | | #ifdef DEBUG_YIELD | |
| #include <sched.h> | | #include <sched.h> | |
| #include <time.h> | | #include <time.h> | |
| #include <pthread.h> | | #include <pthread.h> | |
| #include <unistd.h> | | #include <unistd.h> | |
| | | | |
| #define YIELD_READ (1 << 0) | | #define YIELD_READ (1 << 0) | |
| #define YIELD_WRITE (1 << 1) | | #define YIELD_WRITE (1 << 1) | |
| | | | |
| /* | | /* | |
|
| * Updates without URCU_MB are much slower. Account this in | | * Updates with RCU_SIGNAL are much slower. Account this in the delay. | |
| * the delay. | | | |
| */ | | */ | |
|
| #ifdef URCU_MB | | #ifdef RCU_SIGNAL | |
| /* maximum sleep delay, in us */ | | /* maximum sleep delay, in us */ | |
|
| #define MAX_SLEEP 50 | | | |
| #else | | | |
| #define MAX_SLEEP 30000 | | #define MAX_SLEEP 30000 | |
|
| | | #else | |
| | | #define MAX_SLEEP 50 | |
| #endif | | #endif | |
| | | | |
| extern unsigned int yield_active; | | extern unsigned int yield_active; | |
| extern unsigned int __thread rand_yield; | | extern unsigned int __thread rand_yield; | |
| | | | |
| static inline void debug_yield_read(void) | | static inline void debug_yield_read(void) | |
| { | | { | |
| if (yield_active & YIELD_READ) | | if (yield_active & YIELD_READ) | |
| if (rand_r(&rand_yield) & 0x1) | | if (rand_r(&rand_yield) & 0x1) | |
| usleep(rand_r(&rand_yield) % MAX_SLEEP); | | usleep(rand_r(&rand_yield) % MAX_SLEEP); | |
| | | | |
| skipping to change at line 138 | | skipping to change at line 163 | |
| static inline void debug_yield_write(void) | | static inline void debug_yield_write(void) | |
| { | | { | |
| } | | } | |
| | | | |
| static inline void debug_yield_init(void) | | static inline void debug_yield_init(void) | |
| { | | { | |
| | | | |
| } | | } | |
| #endif | | #endif | |
| | | | |
|
| #ifdef URCU_MB | | /* | |
| static inline void reader_barrier() | | * RCU memory barrier broadcast group. Currently, only broadcast to all pro | |
| | | cess | |
| | | * threads is supported (group 0). | |
| | | * | |
| | | * Slave barriers are only guaranteed to be ordered wrt master barriers. | |
| | | * | |
| | | * The pair ordering is detailed as (O: ordered, X: not ordered) : | |
| | | * slave master | |
| | | * slave X O | |
| | | * master O O | |
| | | */ | |
| | | | |
| | | #define MB_GROUP_ALL 0 | |
| | | #define RCU_MB_GROUP MB_GROUP_ALL | |
| | | | |
| | | #ifdef RCU_MEMBARRIER | |
| | | extern int has_sys_membarrier; | |
| | | | |
| | | static inline void smp_mb_slave(int group) | |
| | | { | |
| | | if (likely(has_sys_membarrier)) | |
| | | barrier(); | |
| | | else | |
| | | smp_mb(); | |
| | | } | |
| | | #endif | |
| | | | |
| | | #ifdef RCU_MB | |
| | | static inline void smp_mb_slave(int group) | |
| { | | { | |
| smp_mb(); | | smp_mb(); | |
| } | | } | |
|
| #else | | #endif | |
| static inline void reader_barrier() | | | |
| | | #ifdef RCU_SIGNAL | |
| | | static inline void smp_mb_slave(int group) | |
| { | | { | |
| barrier(); | | barrier(); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| /* | | /* | |
|
| * The trick here is that RCU_GP_CTR_BIT must be a multiple of 8 so we can | | * The trick here is that RCU_GP_CTR_PHASE must be a multiple of 8 so we ca | |
| use a | | n use | |
| * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | | * a full 8-bits, 16-bits or 32-bits bitmask for the lower order bits. | |
| */ | | */ | |
| #define RCU_GP_COUNT (1UL << 0) | | #define RCU_GP_COUNT (1UL << 0) | |
| /* Use the amount of bits equal to half of the architecture long size */ | | /* Use the amount of bits equal to half of the architecture long size */ | |
|
| #define RCU_GP_CTR_BIT (1UL << (sizeof(long) << 2)) | | #define RCU_GP_CTR_PHASE (1UL << (sizeof(long) << 2)) | |
| #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BIT - 1) | | #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_PHASE - 1) | |
| | | | |
| /* | | /* | |
| * Global quiescent period counter with low-order bits unused. | | * Global quiescent period counter with low-order bits unused. | |
| * Using a int rather than a char to eliminate false register dependencies | | * Using a int rather than a char to eliminate false register dependencies | |
| * causing stalls on some architectures. | | * causing stalls on some architectures. | |
| */ | | */ | |
|
| extern long urcu_gp_ctr; | | extern long rcu_gp_ctr; | |
| | | | |
|
| struct urcu_reader { | | struct rcu_reader { | |
| /* Data used by both reader and synchronize_rcu() */ | | /* Data used by both reader and synchronize_rcu() */ | |
| long ctr; | | long ctr; | |
| char need_mb; | | char need_mb; | |
| /* Data used for registry */ | | /* Data used for registry */ | |
| struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | | struct list_head head __attribute__((aligned(CACHE_LINE_SIZE))); | |
| pthread_t tid; | | pthread_t tid; | |
| }; | | }; | |
| | | | |
|
| extern struct urcu_reader __thread urcu_reader; | | extern struct rcu_reader __thread rcu_reader; | |
| | | | |
| extern int gp_futex; | | extern int gp_futex; | |
| | | | |
| /* | | /* | |
| * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | | * Wake-up waiting synchronize_rcu(). Called from many concurrent threads. | |
| */ | | */ | |
| static inline void wake_up_gp(void) | | static inline void wake_up_gp(void) | |
| { | | { | |
| if (unlikely(uatomic_read(&gp_futex) == -1)) { | | if (unlikely(uatomic_read(&gp_futex) == -1)) { | |
| uatomic_set(&gp_futex, 0); | | uatomic_set(&gp_futex, 0); | |
| | | | |
| skipping to change at line 203 | | skipping to change at line 257 | |
| long v; | | long v; | |
| | | | |
| if (value == NULL) | | if (value == NULL) | |
| return 0; | | return 0; | |
| /* | | /* | |
| * Make sure both tests below are done on the same version of *value | | * Make sure both tests below are done on the same version of *value | |
| * to insure consistency. | | * to insure consistency. | |
| */ | | */ | |
| v = LOAD_SHARED(*value); | | v = LOAD_SHARED(*value); | |
| return (v & RCU_GP_CTR_NEST_MASK) && | | return (v & RCU_GP_CTR_NEST_MASK) && | |
|
| ((v ^ urcu_gp_ctr) & RCU_GP_CTR_BIT); | | ((v ^ rcu_gp_ctr) & RCU_GP_CTR_PHASE); | |
| } | | } | |
| | | | |
| static inline void _rcu_read_lock(void) | | static inline void _rcu_read_lock(void) | |
| { | | { | |
| long tmp; | | long tmp; | |
| | | | |
|
| tmp = urcu_reader.ctr; | | tmp = rcu_reader.ctr; | |
| /* urcu_gp_ctr = RCU_GP_COUNT | (~RCU_GP_CTR_BIT or RCU_GP_CTR_BIT) | | /* | |
| */ | | * rcu_gp_ctr is | |
| | | * RCU_GP_COUNT | (~RCU_GP_CTR_PHASE or RCU_GP_CTR_PHASE) | |
| | | */ | |
| if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | | if (likely(!(tmp & RCU_GP_CTR_NEST_MASK))) { | |
|
| _STORE_SHARED(urcu_reader.ctr, _LOAD_SHARED(urcu_gp_ctr)); | | _STORE_SHARED(rcu_reader.ctr, _LOAD_SHARED(rcu_gp_ctr)); | |
| /* | | /* | |
| * Set active readers count for outermost nesting level befo
re | | * Set active readers count for outermost nesting level befo
re | |
|
| * accessing the pointer. See force_mb_all_threads(). | | * accessing the pointer. See smp_mb_master(). | |
| */ | | */ | |
|
| reader_barrier(); | | smp_mb_slave(RCU_MB_GROUP); | |
| } else { | | } else { | |
|
| _STORE_SHARED(urcu_reader.ctr, tmp + RCU_GP_COUNT); | | _STORE_SHARED(rcu_reader.ctr, tmp + RCU_GP_COUNT); | |
| } | | } | |
| } | | } | |
| | | | |
| static inline void _rcu_read_unlock(void) | | static inline void _rcu_read_unlock(void) | |
| { | | { | |
| long tmp; | | long tmp; | |
| | | | |
|
| tmp = urcu_reader.ctr; | | tmp = rcu_reader.ctr; | |
| /* | | /* | |
| * Finish using rcu before decrementing the pointer. | | * Finish using rcu before decrementing the pointer. | |
|
| * See force_mb_all_threads(). | | * See smp_mb_master(). | |
| */ | | */ | |
| if (likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { | | if (likely((tmp & RCU_GP_CTR_NEST_MASK) == RCU_GP_COUNT)) { | |
|
| reader_barrier(); | | smp_mb_slave(RCU_MB_GROUP); | |
| _STORE_SHARED(urcu_reader.ctr, urcu_reader.ctr - RCU_GP_COUN | | _STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT) | |
| T); | | ; | |
| /* write urcu_reader.ctr before read futex */ | | /* write rcu_reader.ctr before read futex */ | |
| reader_barrier(); | | smp_mb_slave(RCU_MB_GROUP); | |
| wake_up_gp(); | | wake_up_gp(); | |
| } else { | | } else { | |
|
| _STORE_SHARED(urcu_reader.ctr, urcu_reader.ctr - RCU_GP_COUN
T); | | _STORE_SHARED(rcu_reader.ctr, rcu_reader.ctr - RCU_GP_COUNT)
; | |
| } | | } | |
| } | | } | |
| | | | |
| #ifdef __cplusplus | | #ifdef __cplusplus | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| #endif /* _URCU_STATIC_H */ | | #endif /* _URCU_STATIC_H */ | |
| | | | |
End of changes. 25 change blocks. |
| 37 lines changed or deleted | | 95 lines changed or added | |
|