Atomic/SMP update, part 2.
Added new atomic functions, renamed some old ones. Some #defines have
been added for backward compatibility.
Merged the pre- and post-ARMv6 implementations into a single file.
Renamed the semi-private __android_membar_full_smp to USE_SCREAMING_CAPS
since that's more appropriate for a macro.
Added lots of comments.
Note Mac OS X primitives have not been tested.
Change-Id: If827260750aeb61ad5c2b760e30658e29dbb26f2
diff --git a/libcutils/atomic.c b/libcutils/atomic.c
index d818906..4cefa6b 100644
--- a/libcutils/atomic.c
+++ b/libcutils/atomic.c
@@ -27,11 +27,25 @@
#include <libkern/OSAtomic.h>
-void android_atomic_write(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, value, (int32_t*)addr) == 0);
+int32_t android_atomic_acquire_load(volatile int32_t* addr) {
+ int32_t value = *addr;
+ OSMemoryBarrier();
+ return value;
+}
+
+int32_t android_atomic_release_load(volatile int32_t* addr) {
+ OSMemoryBarrier();
+ return *addr;
+}
+
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
+ *addr = value;
+ OSMemoryBarrier();
+}
+
+void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
+ OSMemoryBarrier();
+ *addr = value;
}
int32_t android_atomic_inc(volatile int32_t* addr) {
@@ -47,74 +61,81 @@
}
int32_t android_atomic_and(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue&value, (int32_t*)addr) == 0);
- return oldValue;
+ return OSAtomicAnd32OrigBarrier(value, (int32_t*)addr);
}
int32_t android_atomic_or(int32_t value, volatile int32_t* addr) {
+ return OSAtomicOr32OrigBarrier(value, (int32_t*)addr);
+}
+
+int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
- } while (OSAtomicCompareAndSwap32Barrier(oldValue, oldValue|value, (int32_t*)addr) == 0);
+ } while (android_atomic_acquire_cas(oldValue, value, addr));
return oldValue;
}
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
+int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
+ } while (android_atomic_release_cas(oldValue, value, addr));
return oldValue;
}
-int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
+int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
/* OS X CAS returns zero on failure; invert to return zero on success */
return OSAtomicCompareAndSwap32Barrier(oldvalue, newvalue, (int32_t*)addr) == 0;
}
-int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
+int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
int result = (OSAtomicCompareAndSwap32(oldvalue, newvalue, (int32_t*)addr) == 0);
- if (!result) {
+ if (result == 0) {
/* success, perform barrier */
OSMemoryBarrier();
}
+ return result;
}
/*****************************************************************************/
#elif defined(__i386__) || defined(__x86_64__)
-void android_atomic_write(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
+int32_t android_atomic_acquire_load(volatile int32_t* addr) {
+ int32_t value = *addr;
+ ANDROID_MEMBAR_FULL();
+ return value;
+}
+
+int32_t android_atomic_release_load(volatile int32_t* addr) {
+ ANDROID_MEMBAR_FULL();
+ return *addr;
+}
+
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr) {
+ *addr = value;
+ ANDROID_MEMBAR_FULL();
+}
+
+void android_atomic_release_store(int32_t value, volatile int32_t* addr) {
+ ANDROID_MEMBAR_FULL();
+ *addr = value;
}
int32_t android_atomic_inc(volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+1, addr));
- return oldValue;
+ return android_atomic_add(1, addr);
}
int32_t android_atomic_dec(volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue-1, addr));
- return oldValue;
+ return android_atomic_add(-1, addr);
}
int32_t android_atomic_add(int32_t value, volatile int32_t* addr) {
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue+value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue+value, addr));
return oldValue;
}
@@ -122,7 +143,7 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue&value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue&value, addr));
return oldValue;
}
@@ -130,20 +151,13 @@
int32_t oldValue;
do {
oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, oldValue|value, addr));
+ } while (android_atomic_release_cas(oldValue, oldValue|value, addr));
return oldValue;
}
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr) {
- int32_t oldValue;
- do {
- oldValue = *addr;
- } while (android_atomic_cmpxchg(oldValue, value, addr));
- return oldValue;
-}
-
-int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue, volatile int32_t* addr) {
- android_membar_full();
+/* returns 0 on successful swap */
+static inline int cas(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr) {
int xchg;
asm volatile
(
@@ -156,18 +170,36 @@
return xchg;
}
-int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
+int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
+ int32_t oldValue;
+ do {
+ oldValue = *addr;
+ } while (cas(oldValue, value, addr));
+ ANDROID_MEMBAR_FULL();
+ return oldValue;
+}
+
+int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
+ ANDROID_MEMBAR_FULL();
+ int32_t oldValue;
+ do {
+ oldValue = *addr;
+ } while (cas(oldValue, value, addr));
+ return oldValue;
+}
+
+int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr) {
- int xchg;
- asm volatile
- (
- " lock; cmpxchg %%ecx, (%%edx);"
- " setne %%al;"
- " andl $1, %%eax"
- : "=a" (xchg)
- : "a" (oldvalue), "c" (newvalue), "d" (addr)
- );
- android_membar_full();
+ int xchg = cas(oldvalue, newvalue, addr);
+ if (xchg == 0)
+ ANDROID_MEMBAR_FULL();
+ return xchg;
+}
+
+int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
+ volatile int32_t* addr) {
+ ANDROID_MEMBAR_FULL();
+ int xchg = cas(oldvalue, newvalue, addr);
return xchg;
}