diff --git a/lib/ovs-atomic-clang.h b/lib/ovs-atomic-clang.h index c83afab9ba7..34cc2faa7ec 100644 --- a/lib/ovs-atomic-clang.h +++ b/lib/ovs-atomic-clang.h @@ -53,6 +53,20 @@ typedef enum { (*(DST) = __c11_atomic_load(SRC, ORDER), \ (void) 0) +#define atomic_compare_exchange_strong(DST, EXP, SRC) \ + atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ + memory_order_seq_cst, \ + memory_order_seq_cst) +#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ + __c11_atomic_compare_exchange_strong(DST, EXP, SRC, ORD1, ORD2) + +#define atomic_compare_exchange_weak(DST, EXP, SRC) \ + atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ + memory_order_seq_cst, \ + memory_order_seq_cst) +#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ + __c11_atomic_compare_exchange_weak(DST, EXP, SRC, ORD1, ORD2) + #define atomic_add(RMW, ARG, ORIG) \ atomic_add_explicit(RMW, ARG, ORIG, memory_order_seq_cst) #define atomic_sub(RMW, ARG, ORIG) \ diff --git a/lib/ovs-atomic-gcc4+.h b/lib/ovs-atomic-gcc4+.h index 2a1b278b700..e3dd68ec08a 100644 --- a/lib/ovs-atomic-gcc4+.h +++ b/lib/ovs-atomic-gcc4+.h @@ -108,6 +108,29 @@ atomic_signal_fence(memory_order order OVS_UNUSED) (void) 0; \ }) +#define atomic_compare_exchange_strong(DST, EXP, SRC) \ + ({ \ + typeof(DST) dst__ = (DST); \ + typeof(EXP) expp__ = (EXP); \ + typeof(SRC) src__ = (SRC); \ + typeof(SRC) exp__ = *expp__; \ + typeof(SRC) ret__; \ + \ + ret__ = __sync_val_compare_and_swap(dst__, exp__, src__); \ + if (ret__ != exp__) { \ + *expp__ = ret__; \ + } \ + ret__ == exp__; \ + }) +#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ + ((void) (ORD1), (void) (ORD2), \ + atomic_compare_exchange_strong(DST, EXP, SRC)) +#define atomic_compare_exchange_weak \ + atomic_compare_exchange_strong +#define atomic_compare_exchange_weak_explicit \ + atomic_compare_exchange_strong_explicit + + #define atomic_op__(RMW, OP, ARG, ORIG) \ ({ \ typeof(RMW) rmw__ = (RMW); \ diff --git a/lib/ovs-atomic-gcc4.7+.h b/lib/ovs-atomic-gcc4.7+.h index f465e516b1d..4c197ebe05b 100644 --- a/lib/ovs-atomic-gcc4.7+.h +++ b/lib/ovs-atomic-gcc4.7+.h @@ -47,6 +47,20 @@ typedef enum { (*(DST) = __atomic_load_n(SRC, ORDER), \ (void) 0) +#define atomic_compare_exchange_strong(DST, EXP, SRC) \ + atomic_compare_exchange_strong_explicit(DST, EXP, SRC, \ + memory_order_seq_cst, \ + memory_order_seq_cst) +#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ + __atomic_compare_exchange_n(DST, EXP, SRC, false, ORD1, ORD2) + +#define atomic_compare_exchange_weak(DST, EXP, SRC) \ + atomic_compare_exchange_weak_explicit(DST, EXP, SRC, \ + memory_order_seq_cst, \ + memory_order_seq_cst) +#define atomic_compare_exchange_weak_explicit(DST, EXP, SRC, ORD1, ORD2) \ + __atomic_compare_exchange_n(DST, EXP, SRC, true, ORD1, ORD2) + #define atomic_add(RMW, OPERAND, ORIG) \ atomic_add_explicit(RMW, OPERAND, ORIG, memory_order_seq_cst) #define atomic_sub(RMW, OPERAND, ORIG) \ diff --git a/lib/ovs-atomic-locked.h b/lib/ovs-atomic-locked.h index 438e78c794b..f8f0ba2a579 100644 --- a/lib/ovs-atomic-locked.h +++ b/lib/ovs-atomic-locked.h @@ -20,6 +20,17 @@ void atomic_unlock__(void *); atomic_unlock__(SRC), \ (void) 0) +/* XXX: Evaluates EXP multiple times. */ +#define atomic_compare_exchange_locked(DST, EXP, SRC) \ + (atomic_lock__(DST), \ + (*(DST) == *(EXP) \ + ? (*(DST) = (SRC), \ + atomic_unlock__(DST), \ + true) \ + : (*(EXP) = *(DST), \ + atomic_unlock__(DST), \ + false))) + #define atomic_op_locked_add += #define atomic_op_locked_sub -= #define atomic_op_locked_or |= diff --git a/lib/ovs-atomic-pthreads.h b/lib/ovs-atomic-pthreads.h index 33270c6a2a2..12234e79e8a 100644 --- a/lib/ovs-atomic-pthreads.h +++ b/lib/ovs-atomic-pthreads.h @@ -67,6 +67,16 @@ atomic_signal_fence(memory_order order OVS_UNUSED) #define atomic_read_explicit(SRC, DST, ORDER) \ ((void) (ORDER), atomic_read(SRC, DST)) +#define atomic_compare_exchange_strong(DST, EXP, SRC) \ + atomic_compare_exchange_locked(DST, EXP, SRC) +#define atomic_compare_exchange_strong_explicit(DST, EXP, SRC, ORD1, ORD2) \ + ((void) (ORD1), (void) (ORD2), \ + atomic_compare_exchange_strong(DST, EXP, SRC)) +#define atomic_compare_exchange_weak \ + atomic_compare_exchange_strong +#define atomic_compare_exchange_weak_explicit \ + atomic_compare_exchange_strong_explicit + #define atomic_add(RMW, ARG, ORIG) atomic_op_locked(RMW, add, ARG, ORIG) #define atomic_sub(RMW, ARG, ORIG) atomic_op_locked(RMW, sub, ARG, ORIG) #define atomic_or( RMW, ARG, ORIG) atomic_op_locked(RMW, or, ARG, ORIG) diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h index c1d9fcf3e0c..95142f5c9db 100644 --- a/lib/ovs-atomic.h +++ b/lib/ovs-atomic.h @@ -161,7 +161,7 @@ * In this section, A is an atomic type and C is the corresponding non-atomic * type. * - * The "store" primitives match C11: + * The "store" and "compare_exchange" primitives match C11: * * void atomic_store(A *object, C value); * void atomic_store_explicit(A *object, C value, memory_order); @@ -169,6 +169,32 @@ * Atomically stores 'value' into '*object', respecting the given * memory order (or memory_order_seq_cst for atomic_store()). * + * bool atomic_compare_exchange_strong(A *object, C *expected, C desired); + * bool atomic_compare_exchange_weak(A *object, C *expected, C desired); + * bool atomic_compare_exchange_strong_explicit(A *object, C *expected, + * C desired, + * memory_order success, + * memory_order failure); + * bool atomic_compare_exchange_weak_explicit(A *object, C *expected, + * C desired, + * memory_order success, + * memory_order failure); + * + * Atomically loads '*object' and compares it with '*expected' and if + * equal, stores 'desired' into '*object' (an atomic read-modify-write + * operation) and returns true, and if non-equal, stores the actual + * value of '*object' into '*expected' (an atomic load operation) and + * returns false. The memory order for the successful case (atomic + * read-modify-write operation) is 'success', and for the unsuccessful + * case (atomic load operation) 'failure'. 'failure' may not be + * stronger than 'success'. + * + * The weak forms may fail (returning false) also when '*object' equals + * '*expected'. The strong form can be implemented by the weak form in + * a loop. Some platforms can implement the weak form more + * efficiently, so it should be used if the application will need to + * loop anyway. + * * The following primitives differ from the C11 ones (and have different names) * because there does not appear to be a way to implement the standard * primitives in standard C: