arch.h   arch.h 
skipping to change at line 36 skipping to change at line 36
#include <urcu/config.h> #include <urcu/config.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define CONFIG_HAVE_MEM_COHERENCY #define CONFIG_HAVE_MEM_COHERENCY
#define CACHE_LINE_SIZE 128 #define CACHE_LINE_SIZE 128
#ifdef CONFIG_URCU_HAVE_FENCE #ifdef CONFIG_RCU_HAVE_FENCE
#define mb() asm volatile("mfence":::"memory") #define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory") #define rmb() asm volatile("lfence":::"memory")
#define wmb() asm volatile("sfence"::: "memory") #define wmb() asm volatile("sfence"::: "memory")
#else #else
/* /*
* Some non-Intel clones support out of order store. wmb() ceases to be a * Some non-Intel clones support out of order store. wmb() ceases to be a
* nop for these. * nop for these.
*/ */
#define mb() asm volatile("lock; addl $0,0(%%esp)":::"memory") #define mb() asm volatile("lock; addl $0,0(%%esp)":::"memory")
#define rmb() asm volatile("lock; addl $0,0(%%esp)":::"memory") #define rmb() asm volatile("lock; addl $0,0(%%esp)":::"memory")
skipping to change at line 65 skipping to change at line 65
* #define wmb() wmc() * #define wmb() wmc()
* #define mc() arch_cache_flush() * #define mc() arch_cache_flush()
* #define rmc() arch_cache_flush_read() * #define rmc() arch_cache_flush_read()
* #define wmc() arch_cache_flush_write() * #define wmc() arch_cache_flush_write()
*/ */
#define mc() barrier() #define mc() barrier()
#define rmc() barrier() #define rmc() barrier()
#define wmc() barrier() #define wmc() barrier()
#ifdef CONFIG_URCU_SMP #ifdef CONFIG_RCU_SMP
#define smp_mb() mb() #define smp_mb() mb()
#define smp_rmb() rmb() #define smp_rmb() rmb()
#define smp_wmb() wmb() #define smp_wmb() wmb()
#define smp_mc() mc() #define smp_mc() mc()
#define smp_rmc() rmc() #define smp_rmc() rmc()
#define smp_wmc() wmc() #define smp_wmc() wmc()
#else #else
#define smp_mb() barrier() #define smp_mb() barrier()
#define smp_rmb() barrier() #define smp_rmb() barrier()
#define smp_wmb() barrier() #define smp_wmb() barrier()
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 config.h   config.h 
/* urcu/config.h. Generated from config.h.in by configure. */ /* urcu/config.h. Generated from config.h.in by configure. */
/* urcu/config.h.in. Manually generatad for control over the contained defs . */ /* urcu/config.h.in. Manually generatad for control over the contained defs . */
/* Defined when on a system that has memory fence instructions. */ /* Defined when on a system that has memory fence instructions. */
/* #undef CONFIG_URCU_HAVE_FENCE */ /* #undef CONFIG_RCU_HAVE_FENCE */
/* Defined when on a system with futex support. */ /* Defined when on a system with futex support. */
#define CONFIG_URCU_HAVE_FUTEX 1 #define CONFIG_RCU_HAVE_FUTEX 1
/* Enable SMP support. With SMP support enabled, uniprocessors are also /* Enable SMP support. With SMP support enabled, uniprocessors are also
supported. With SMP support disabled, UP systems work fine, but the supported. With SMP support disabled, UP systems work fine, but the
behavior of SMP systems is undefined. */ behavior of SMP systems is undefined. */
#define CONFIG_URCU_SMP 1 #define CONFIG_RCU_SMP 1
/* Compatibility mode for i386 which lacks cmpxchg instruction. */ /* Compatibility mode for i386 which lacks cmpxchg instruction. */
/* #undef CONFIG_URCU_COMPAT_ARCH */ /* #undef CONFIG_RCU_COMPAT_ARCH */
 End of changes. 4 change blocks. 
3 lines changed or deleted 3 lines changed or added


 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-bp.h   urcu-bp.h 
skipping to change at line 100 skipping to change at line 100
* In the bulletproof version, the following functions are no-ops. * In the bulletproof version, the following functions are no-ops.
*/ */
static inline void rcu_register_thread(void) static inline void rcu_register_thread(void)
{ {
} }
static inline void rcu_unregister_thread(void) static inline void rcu_unregister_thread(void)
{ {
} }
static inline void urcu_init(void) static inline void rcu_init(void)
{ {
} }
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_BP_H */ #endif /* _URCU_BP_H */
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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


 urcu.h   urcu.h 
skipping to change at line 95 skipping to change at line 95
extern void synchronize_rcu(void); extern void synchronize_rcu(void);
/* /*
* Reader thread registration. * Reader thread registration.
*/ */
extern void rcu_register_thread(void); extern void rcu_register_thread(void);
extern void rcu_unregister_thread(void); extern void rcu_unregister_thread(void);
/* /*
* Explicit urcu initialization, for "early" use within library constructor s. * Explicit rcu initialization, for "early" use within library constructors .
*/ */
extern void urcu_init(void); extern void rcu_init(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* _URCU_H */ #endif /* _URCU_H */
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/