summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--osdep/atomics.h11
-rw-r--r--wscript1
2 files changed, 12 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
diff --git a/wscript b/wscript
index affd261b16..a73c1f1a76 100644
--- a/wscript
+++ b/wscript
@@ -134,6 +134,7 @@ main_dependencies = [
'desc': 'compiler support for __sync built-ins',
'func': check_statement('stdint.h',
'int64_t test = 0;'
+ '__typeof__(test) x = ({int a = 1; a;});'
'test = __sync_add_and_fetch(&test, 1)'),
'deps_neg': [ 'stdatomic', 'atomic-builtins' ],
}, {