ovsrcu_set() and ovsrcu_init() look like functions, so users are justified in expecting the arguments to be evalueated before any of the body of ovsrcu_set or ovsrcu_init().
With ovs-atomic-pthreads, a fallback ovs-atomics implementation used when no C11 atomics are available or with GCC older than 4.0, the prior definitions led to nested mutex locking when the 'VALUE' argument was an atomic_read(). This is resolved by ensuring function argument semantics for the parameters. For non-GCC compilers this is done with an inline function. GCC implementation of ovs-rcu does not fix the RCU variable type, so a GCC macro needs to be used instead. Reported-by: YAMAMOTO Takashi <yamam...@valinux.co.jp> Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/ovs-rcu.h | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/ovs-rcu.h b/lib/ovs-rcu.h index c3e06ad..e27dfad 100644 --- a/lib/ovs-rcu.h +++ b/lib/ovs-rcu.h @@ -131,6 +131,20 @@ CONST_CAST(TYPE, ovsrcu_get__(TYPE, VAR, memory_order_consume)) #define ovsrcu_get_protected(TYPE, VAR) \ CONST_CAST(TYPE, ovsrcu_get__(TYPE, VAR, memory_order_relaxed)) + +/* 'VALUE' may be an atomic operation, which must be evaluated before + * any of the body of the atomic_store_explicit. Since the type of + * 'VAR' is not fixed, we cannot use an inline function to get + * function semantics for this. */ +#define ovsrcu_set__(VAR, VALUE, ORDER) \ + ({ \ + typeof(VAR) var__ = (VAR); \ + typeof(VALUE) value__ = (VALUE); \ + memory_order order__ = (ORDER); \ + \ + atomic_store_explicit(&var__->p, value__, order__); \ + (void *) 0; \ + }) #else /* not GNU C */ struct ovsrcu_pointer { ATOMIC(void *) p; }; #define OVSRCU_TYPE(TYPE) struct ovsrcu_pointer @@ -147,6 +161,13 @@ ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_consume)) #define ovsrcu_get_protected(TYPE, VAR) \ CONST_CAST(TYPE, ovsrcu_get__(VAR, memory_order_relaxed)) + +static inline void ovsrcu_set__(struct ovsrcu_pointer *pointer, + const void *value, + memory_order order) +{ + atomic_store_explicit(&pointer->p, CONST_CAST(void *, value), order); +} #endif /* Writes VALUE to the RCU-protected pointer whose address is VAR. @@ -154,13 +175,13 @@ ovsrcu_get__(const struct ovsrcu_pointer *pointer, memory_order order) * Users require external synchronization (e.g. a mutex). See "Usage" above * for an example. */ #define ovsrcu_set(VAR, VALUE) \ - atomic_store_explicit(&(VAR)->p, VALUE, memory_order_release) + 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_init(VAR, VALUE) \ - atomic_store_explicit(&(VAR)->p, VALUE, memory_order_relaxed) + ovsrcu_set__(VAR, VALUE, memory_order_relaxed) /* Calls FUNCTION passing ARG as its pointer-type argument following the next * grace period. See "Usage" above for example. */ -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev