[ovs-dev] [PATCH v3 4/8] ovs-atomic: Fix GCC4+ atomic_flag.

Jarno Rajahalme jrajahalme at nicira.com
Thu Jul 31 22:21:50 UTC 2014


The default memory order for atomic_flag is documented to be
memory_order_seq_cst (as in C11), but the GCC4+ implementation only
used the GCC builtins, which provide acquire and release semantics
only.  Additional barriers are needed for in other cases.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
 lib/ovs-atomic-gcc4+.h |   40 +++++++++++++++++++++++++---------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/lib/ovs-atomic-gcc4+.h b/lib/ovs-atomic-gcc4+.h
index bb889c6..756696b 100644
--- a/lib/ovs-atomic-gcc4+.h
+++ b/lib/ovs-atomic-gcc4+.h
@@ -167,27 +167,37 @@ typedef struct {
 #define ATOMIC_FLAG_INIT { false }
 
 static inline bool
-atomic_flag_test_and_set(volatile atomic_flag *object)
-{
-    return __sync_lock_test_and_set(&object->b, 1);
-}
-
-static inline bool
 atomic_flag_test_and_set_explicit(volatile atomic_flag *object,
-                                  memory_order order OVS_UNUSED)
+                                  memory_order order)
 {
-    return atomic_flag_test_and_set(object);
-}
+    bool old;
 
-static inline void
-atomic_flag_clear(volatile atomic_flag *object)
-{
-    __sync_lock_release(&object->b);
+    /* __sync_lock_test_and_set() by itself is an acquire barrier.
+     * For anything higher additional barriers are needed. */
+    if (order > memory_order_acquire) {
+        atomic_thread_fence(order);
+    }
+    old = __sync_lock_test_and_set(&object->b, 1);
+    atomic_thread_fence_if_seq_cst(order);
+
+    return old;
 }
 
+#define atomic_flag_test_and_set(FLAG)                                  \
+    atomic_flag_test_and_set_explicit(FLAG, memory_order_seq_cst)
+
 static inline void
 atomic_flag_clear_explicit(volatile atomic_flag *object,
-                           memory_order order OVS_UNUSED)
+                           memory_order order)
 {
-    atomic_flag_clear(object);
+    /* __sync_lock_release() by itself is a release barrier.  For
+     * anything else additional barrier may be needed. */
+    if (order != memory_order_release) {
+        atomic_thread_fence(order);
+    }
+    __sync_lock_release(&object->b);
+    atomic_thread_fence_if_seq_cst(order);
 }
+
+#define atomic_flag_clear(FLAG)                                 \
+    atomic_flag_clear_explicit(FLAG, memory_order_seq_cst)
-- 
1.7.10.4




More information about the dev mailing list