summaryrefslogtreecommitdiffstats
path: root/osdep/atomics.h
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-11-09 15:12:54 +0100
committerwm4 <wm4@nowhere>2014-11-09 15:12:54 +0100
commit0025f0042f68b664ab9e62ebd0279e0485f3eaa8 (patch)
treebfa8a6f7fa32b02cbb344025727c9d252db3498f /osdep/atomics.h
parent5db0fbd95ec8790cd1a133bb57f701c5c9f970c0 (diff)
downloadmpv-0025f0042f68b664ab9e62ebd0279e0485f3eaa8.tar.bz2
mpv-0025f0042f68b664ab9e62ebd0279e0485f3eaa8.tar.xz
atomics: add atomic_compare_exchange_strong()
As usual, we use C11 semantics, and emulate it if <stdatomic.h> is not available. It's a bit messy with __sync_val_compare_and_swap(). We assume it has "strong" semantics (it can't fail sporadically), but I'm not sure if this is really the case. On the other hand, weak semantics don't seem to be possible, since the builtin can't distinguish between the two failure cases that could occur. Also, to match the C11 interface, use of gcc builtins is unavoidable. Add a check to the build system to make sure the compiler supports them (although I don't think there's any compiler which supports __sync_*, but not these extensions). Needed for the following commit.
Diffstat (limited to 'osdep/atomics.h')
-rw-r--r--osdep/atomics.h11
1 files changed, 11 insertions, 0 deletions
diff --git a/osdep/atomics.h b/osdep/atomics.h
index e5fb717a78..39c741acd7 100644
--- a/osdep/atomics.h
+++ b/osdep/atomics.h
@@ -49,6 +49,9 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
__atomic_store_n(&(p)->v, val, __ATOMIC_SEQ_CST)
#define atomic_fetch_add(a, b) \
__atomic_fetch_add(&(a)->v, b, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong(a, b, c) \
+ __atomic_compare_exchange_n(&(a)->v, b, c, 0, __ATOMIC_SEQ_CST, \
+ __ATOMIC_SEQ_CST)
#elif HAVE_SYNC_BUILTINS
@@ -58,6 +61,12 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
(__sync_synchronize(), (p)->v = (val), __sync_synchronize())
#define atomic_fetch_add(a, b) \
__sync_fetch_and_add(&(a)->v, b)
+// Assumes __sync_val_compare_and_swap is "strong" (using the C11 meaning).
+#define atomic_compare_exchange_strong(p, old, new) \
+ ({ __typeof__((p)->v) val_ = __sync_val_compare_and_swap(&(p)->v, *(old), new); \
+ bool ok_ = val_ == *(old); \
+ if (!ok_) *(old) = val_; \
+ ok_; })
#else
@@ -66,6 +75,8 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
#define atomic_load(p) ((p)->v)
#define atomic_store(p, val) ((p)->v = (val))
#define atomic_fetch_add(a, b) (((a)->v += (b)) - (b))
+#define atomic_compare_exchange_strong(p, old, new) \
+ ((p)->v == *(old) ? ((p)->v = (new), 1) : (*(old) = (p)->v, 0))
#undef HAVE_ATOMICS
#define HAVE_ATOMICS 0