Compiler implementations may provide sub-optimal support for a memory_order passed in as a run-time value (ref. https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html).
Document that OVS atomics require the memory order to be passed in as a compile-time constant, and modify ovs-atomic, ovs-rcu, and cmap to comply with this. Signed-off-by: Jarno Rajahalme <[email protected]> --- v2: Also update ovs-rcu accordingly. lib/cmap.c | 18 +++++++++------ lib/ovs-atomic-gcc4+.h | 10 ++++----- lib/ovs-atomic.h | 3 +++ lib/ovs-rcu.h | 57 +++++++++++++++++++++++++++++++++--------------- 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/lib/cmap.c b/lib/cmap.c index ba744cc..60629b1 100644 --- a/lib/cmap.c +++ b/lib/cmap.c @@ -163,19 +163,23 @@ struct cmap_impl { }; BUILD_ASSERT_DECL(sizeof(struct cmap_impl) == CACHE_LINE_SIZE); -static uint32_t cmap_get_hash__(const atomic_uint32_t *hash, - memory_order order) +static inline uint32_t cmap_get_hash(const atomic_uint32_t *hash) { uint32_t hash__; - atomic_read_explicit(CONST_CAST(ATOMIC(uint32_t) *, hash), &hash__, order); + atomic_read_explicit(CONST_CAST(ATOMIC(uint32_t) *, hash), &hash__, + memory_order_acquire); return hash__; } -#define cmap_get_hash(HASH) \ - cmap_get_hash__(HASH, memory_order_acquire) -#define cmap_get_hash_protected(HASH) \ - cmap_get_hash__(HASH, memory_order_relaxed) +static inline uint32_t cmap_get_hash_protected(const atomic_uint32_t *hash) +{ + uint32_t hash__; + + atomic_read_explicit(CONST_CAST(ATOMIC(uint32_t) *, hash), &hash__, + memory_order_relaxed); + return hash__; +} static struct cmap_impl *cmap_rehash(struct cmap *, uint32_t mask); diff --git a/lib/ovs-atomic-gcc4+.h b/lib/ovs-atomic-gcc4+.h index 9a79f7e..bb889c6 100644 --- a/lib/ovs-atomic-gcc4+.h +++ b/lib/ovs-atomic-gcc4+.h @@ -63,7 +63,7 @@ atomic_thread_fence_if_seq_cst(memory_order order) } static inline void -atomic_signal_fence(memory_order order OVS_UNUSED) +atomic_signal_fence(memory_order order) { if (order != memory_order_relaxed) { asm volatile("" : : : "memory"); @@ -80,12 +80,11 @@ atomic_signal_fence(memory_order order OVS_UNUSED) ({ \ typeof(DST) dst__ = (DST); \ typeof(SRC) src__ = (SRC); \ - memory_order order__ = (ORDER); \ \ if (IS_LOCKLESS_ATOMIC(*dst__)) { \ - atomic_thread_fence(order__); \ + atomic_thread_fence(ORDER); \ *dst__ = src__; \ - atomic_thread_fence_if_seq_cst(order__); \ + atomic_thread_fence_if_seq_cst(ORDER); \ } else { \ atomic_store_locked(dst__, src__); \ } \ @@ -97,10 +96,9 @@ atomic_signal_fence(memory_order order OVS_UNUSED) ({ \ typeof(DST) dst__ = (DST); \ typeof(SRC) src__ = (SRC); \ - memory_order order__ = (ORDER); \ \ if (IS_LOCKLESS_ATOMIC(*src__)) { \ - atomic_thread_fence_if_seq_cst(order__); \ + atomic_thread_fence_if_seq_cst(ORDER); \ *dst__ = *src__; \ } else { \ atomic_read_locked(src__, dst__); \ diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h index fcd7131..78229a7 100644 --- a/lib/ovs-atomic.h +++ b/lib/ovs-atomic.h @@ -173,6 +173,9 @@ * whole system, providing a total order for stores an all atomic * variables. * + * OVS atomics require the memory_order to be passed as a compile-time constant + * value. + * * The following functions insert explicit barriers. Most of the other atomic * functions also include barriers. * diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h index 96b3233..47781d8 100644 --- a/lib/ovs-rcu.h +++ b/lib/ovs-rcu.h @@ -143,48 +143,71 @@ ({ \ typeof(VAR) ovsrcu_var = (VAR); \ typeof(VALUE) ovsrcu_value = (VALUE); \ - memory_order ovsrcu_order = (ORDER); \ \ - atomic_store_explicit(&ovsrcu_var->p, ovsrcu_value, ovsrcu_order); \ + atomic_store_explicit(&ovsrcu_var->p, ovsrcu_value, ORDER); \ (void *) 0; \ }) + +/* Writes VALUE to the RCU-protected pointer whose address is VAR. + * + * Users require external synchronization (e.g. a mutex). See "Usage" above + * for an example. */ +#define ovsrcu_set(VAR, VALUE) \ + ovsrcu_set__(VAR, VALUE, memory_order_release) + +/* This can be used for initializing RCU pointers before any readers can + * see them. A later ovsrcu_set() needs to make the bigger structure this + * is part of visible to the readers. */ +#define ovsrcu_set_hidden(VAR, VALUE) \ + ovsrcu_set__(VAR, VALUE, memory_order_relaxed) + #else /* not GNU C */ + struct ovsrcu_pointer { ATOMIC(void *) p; }; #define OVSRCU_TYPE(TYPE) struct ovsrcu_pointer #define OVSRCU_TYPE_INITIALIZER { NULL } static inline void * -ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) +ovsrcu_get__(const struct ovsrcu_pointer *pointer) { void *value; atomic_read_explicit(&CONST_CAST(struct ovsrcu_pointer *, pointer)->p, - &value, order); + &value, memory_order_consume); return value; } -#define ovsrcu_get(TYPE, VAR) \ - CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_consume)) -#define ovsrcu_get_protected(TYPE, VAR) \ - CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_relaxed)) +#define ovsrcu_get(TYPE, VAR) CONST_CAST(TYPE, ovsrcu_get__(VAR)) -static inline void ovsrcu_set__(struct ovsrcu_pointer *pointer, - const void *value, - memory_order order) +static inline void * +ovsrcu_get_protected__(const struct ovsrcu_pointer *pointer) { - atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), order); + void *value; + atomic_read_explicit(&CONST_CAST(struct ovsrcu_pointer *, pointer)->p, + &value, memory_order_relaxed); + return value; } -#endif +#define ovsrcu_get_protected(TYPE, VAR) \ + CONST_CAST(TYPE, ovsrcu_get_protected__(VAR)) /* Writes VALUE to the RCU-protected pointer whose address is VAR. * * Users require external synchronization (e.g. a mutex). See "Usage" above * for an example. */ -#define ovsrcu_set(VAR, VALUE) \ - ovsrcu_set__(VAR, VALUE, memory_order_release) +static inline void ovsrcu_set(struct ovsrcu_pointer *pointer, + const void *value) +{ + atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), + memory_order_release); +} /* This can be used for initializing RCU pointers before any readers can * see them. A later ovsrcu_set() needs to make the bigger structure this * is part of visible to the readers. */ -#define ovsrcu_set_hidden(VAR, VALUE) \ - ovsrcu_set__(VAR, VALUE, memory_order_relaxed) +static inline void ovsrcu_set_hidden(struct ovsrcu_pointer *pointer, + const void *value) +{ + atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), + memory_order_relaxed); +} +#endif /* This can be used for initializing RCU pointers before any readers are * executing. */ -- 1.7.10.4 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
