From: Jarno Rajahalme Date: Tue, 5 Aug 2014 20:51:19 +0000 (-0700) Subject: ovs-atomic: Fix GCC4+ atomic_flag. X-Git-Tag: v2.12.3~8501 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=91645580722ca44f1617bd3d343f054fc7b4967b;p=mirror_ovs.git ovs-atomic: Fix GCC4+ atomic_flag. 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 Acked-by: Ben Pfaff --- diff --git a/lib/ovs-atomic-gcc4+.h b/lib/ovs-atomic-gcc4+.h index bb889c69f..756696b84 100644 --- a/lib/ovs-atomic-gcc4+.h +++ b/lib/ovs-atomic-gcc4+.h @@ -166,28 +166,38 @@ typedef struct { } atomic_flag; #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)