diff options
author | Andy McFadden <fadden@android.com> | 2010-05-30 21:20:45 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-05-30 21:20:45 -0700 |
commit | 8264358f5b59592d7e8d2902edf9a5c316cb6723 (patch) | |
tree | eecac1070c19976701ef83712590b63ab766125a /include | |
parent | 0e67a037488c3b5a410ba301c408010120264f0b (diff) | |
parent | 8dfa47da8cb33ebaf7aae6db6548e75ed86e8f1e (diff) | |
download | system_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.h | 18 | ||||
-rw-r--r-- | include/cutils/atomic.h | 99 |
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" |