Add support for atomic compare_exchange operations.
Signed-off-by: Jarno Rajahalme <[email protected]>
---
v2: Split to a separate patch, no change.
lib/ovs-atomic-clang.h | 14 ++++++++++++++
lib/ovs-atomic-gcc4+.h | 23 +++++++++++++++++++++++
lib/ovs-atomic-gcc4.7+.h | 14 ++++++++++++++
lib/ovs-atomic-locked.h | 11 +++++++++++
lib/ovs-atomic-pthreads.h | 10 ++++++++++
lib/ovs-atomic.h | 28 +++++++++++++++++++++++++++-
6 files changed, 99 insertions(+), 1 deletion(-)
diff --git a/lib/ovs-atomic-clang.h b/lib/ovs-atomic-clang.h
index c83afab..34cc2fa 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 2a1b278..e3dd68e 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 f465e51..4c197eb 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 438e78c..f8f0ba2 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 33270c6..12234e7 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 c1d9fcf..95142f5 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:
--
1.7.10.4
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev