summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorAndy McFadden <fadden@android.com>2010-05-30 21:20:45 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2010-05-30 21:20:45 -0700
commit8264358f5b59592d7e8d2902edf9a5c316cb6723 (patch)
treeeecac1070c19976701ef83712590b63ab766125a /include
parent0e67a037488c3b5a410ba301c408010120264f0b (diff)
parent8dfa47da8cb33ebaf7aae6db6548e75ed86e8f1e (diff)
downloadsystem_core-8264358f5b59592d7e8d2902edf9a5c316cb6723.zip
system_core-8264358f5b59592d7e8d2902edf9a5c316cb6723.tar.gz
system_core-8264358f5b59592d7e8d2902edf9a5c316cb6723.tar.bz2
am 8dfa47da: Atomic/SMP update, part 2.
Diffstat (limited to 'include')
-rw-r--r--include/cutils/atomic-inline.h18
-rw-r--r--include/cutils/atomic.h99
2 files changed, 87 insertions, 30 deletions
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 4f5ddf7..1c23be9 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -27,6 +27,12 @@
*
* Anything that does include this file must set ANDROID_SMP to either
* 0 or 1, indicating compilation for UP or SMP, respectively.
+ *
+ * Macros defined in this header:
+ *
+ * void ANDROID_MEMBAR_FULL(void)
+ * Full memory barrier. Provides a compiler reordering barrier, and
+ * on SMP systems emits an appropriate instruction.
*/
#if !defined(ANDROID_SMP)
@@ -55,17 +61,17 @@ extern "C" {
* This will fail on plain 16-bit Thumb.
*/
#if defined(__ARM_HAVE_DMB)
-# define __android_membar_full_smp() \
+# define _ANDROID_MEMBAR_FULL_SMP() \
do { __asm__ __volatile__ ("dmb" ::: "memory"); } while (0)
#else
-# define __android_membar_full_smp() ARM_SMP_defined_but_no_DMB()
+# define _ANDROID_MEMBAR_FULL_SMP() ARM_SMP_defined_but_no_DMB()
#endif
#elif defined(__i386__) || defined(__x86_64__)
/*
* For recent x86, we can use the SSE2 mfence instruction.
*/
-# define __android_membar_full_smp() \
+# define _ANDROID_MEMBAR_FULL_SMP() \
do { __asm__ __volatile__ ("mfence" ::: "memory"); } while (0)
#else
@@ -73,7 +79,7 @@ extern "C" {
* Implementation not defined for this platform. Hopefully we're building
* in uniprocessor mode.
*/
-# define __android_membar_full_smp() SMP_barrier_not_defined_for_platform()
+# define _ANDROID_MEMBAR_FULL_SMP() SMP_barrier_not_defined_for_platform()
#endif
@@ -88,9 +94,9 @@ extern "C" {
* be stale. Other CPUs may do less, but the end result is equivalent.
*/
#if ANDROID_SMP != 0
-# define android_membar_full() __android_membar_full_smp()
+# define ANDROID_MEMBAR_FULL() _ANDROID_MEMBAR_FULL_SMP()
#else
-# define android_membar_full() \
+# define ANDROID_MEMBAR_FULL() \
do { __asm__ __volatile__ ("" ::: "memory"); } while (0)
#endif
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index 8e12902..0200709 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -25,51 +25,102 @@ extern "C" {
#endif
/*
- * Unless otherwise noted, the operations below perform a full fence before
- * the atomic operation on SMP systems ("release" semantics).
+ * A handful of basic atomic operations. The appropriate pthread
+ * functions should be used instead of these whenever possible.
+ *
+ * The "acquire" and "release" terms can be defined intuitively in terms
+ * of the placement of memory barriers in a simple lock implementation:
+ * - wait until compare-and-swap(lock-is-free --> lock-is-held) succeeds
+ * - barrier
+ * - [do work]
+ * - barrier
+ * - store(lock-is-free)
+ * In very crude terms, the initial (acquire) barrier prevents any of the
+ * "work" from happening before the lock is held, and the later (release)
+ * barrier ensures that all of the work happens before the lock is released.
+ * (Think of cached writes, cache read-ahead, and instruction reordering
+ * around the CAS and store instructions.)
+ *
+ * The barriers must apply to both the compiler and the CPU. Note it is
+ * legal for instructions that occur before an "acquire" barrier to be
+ * moved down below it, and for instructions that occur after a "release"
+ * barrier to be moved up above it.
+ *
+ * The ARM-driven implementation we use here is short on subtlety,
+ * and actually requests a full barrier from the compiler and the CPU.
+ * The only difference between acquire and release is in whether they
+ * are issued before or after the atomic operation with which they
+ * are associated. To ease the transition to C/C++ atomic intrinsics,
+ * you should not rely on this, and instead assume that only the minimal
+ * acquire/release protection is provided.
+ *
+ * NOTE: all int32_t* values are expected to be aligned on 32-bit boundaries.
+ * If they are not, atomicity is not guaranteed.
*/
-void android_atomic_write(int32_t value, volatile int32_t* addr);
-
/*
- * all these atomic operations return the previous value
+ * Basic arithmetic and bitwise operations. These all provide a
+ * barrier with "release" ordering, and return the previous value.
+ *
+ * These have the same characteristics (e.g. what happens on overflow)
+ * as the equivalent non-atomic C operations.
*/
-
int32_t android_atomic_inc(volatile int32_t* addr);
int32_t android_atomic_dec(volatile int32_t* addr);
-
int32_t android_atomic_add(int32_t value, volatile int32_t* addr);
int32_t android_atomic_and(int32_t value, volatile int32_t* addr);
int32_t android_atomic_or(int32_t value, volatile int32_t* addr);
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr);
+/*
+ * Perform an atomic load with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit read
+ * from a 32-bit aligned address is atomic on all supported platforms.
+ */
+int32_t android_atomic_acquire_load(volatile int32_t* addr);
+int32_t android_atomic_release_load(volatile int32_t* addr);
+
+/*
+ * Perform an atomic store with "acquire" or "release" ordering.
+ *
+ * This is only necessary if you need the memory barrier. A 32-bit write
+ * to a 32-bit aligned address is atomic on all supported platforms.
+ */
+void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
+void android_atomic_release_store(int32_t value, volatile int32_t* addr);
/*
- * cmpxchg returns zero if the new value was successfully written. This
- * will only happen when *addr == oldvalue.
+ * Unconditional swap operation with "acquire" or "release" ordering.
*
- * (The return value is inverted from implementations on other platforms, but
- * matches the ARM ldrex/strex sematics. Note also this is a compare-and-set
- * operation, not a compare-and-exchange operation, since we don't return
- * the original value.)
+ * Stores the new value at *addr, and returns the previous value.
*/
-int android_atomic_cmpxchg(int32_t oldvalue, int32_t newvalue,
- volatile int32_t* addr);
+int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr);
+int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr);
/*
- * Same basic operation as android_atomic_cmpxchg, but with "acquire"
- * semantics. The memory barrier, if required, is performed after the
- * new value is stored. Useful for acquiring a spin lock.
+ * Compare-and-set operation with "acquire" or "release" ordering.
+ *
+ * This returns zero if the new value was successfully stored, which will
+ * only happen when *addr == oldvalue.
+ *
+ * (The return value is inverted from implementations on other platforms,
+ * but matches the ARM ldrex/strex result.)
+ *
+ * Implementations that use the release CAS in a loop may be less efficient
+ * than possible, because we re-issue the memory barrier on each iteration.
*/
-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 android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr);
/*
- * Perform an atomic store with "release" semantics. The memory barrier,
- * if required, is performed before the store instruction. Useful for
- * releasing a spin lock.
+ * Aliases for code using an older version of this header. These are now
+ * deprecated and should not be used. The definitions will be removed
+ * in a future release.
*/
-#define android_atomic_release_store android_atomic_write
+#define android_atomic_write android_atomic_release_store
+#define android_atomic_cmpxchg android_atomic_release_cas
#ifdef __cplusplus
} // extern "C"