michael@0: /* michael@0: * Copyright (C) 2007 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #ifndef ANDROID_CUTILS_ATOMIC_H michael@0: #define ANDROID_CUTILS_ATOMIC_H michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef __cplusplus michael@0: extern "C" { michael@0: #endif michael@0: michael@0: /* michael@0: * A handful of basic atomic operations. The appropriate pthread michael@0: * functions should be used instead of these whenever possible. michael@0: * michael@0: * The "acquire" and "release" terms can be defined intuitively in terms michael@0: * of the placement of memory barriers in a simple lock implementation: michael@0: * - wait until compare-and-swap(lock-is-free --> lock-is-held) succeeds michael@0: * - barrier michael@0: * - [do work] michael@0: * - barrier michael@0: * - store(lock-is-free) michael@0: * In very crude terms, the initial (acquire) barrier prevents any of the michael@0: * "work" from happening before the lock is held, and the later (release) michael@0: * barrier ensures that all of the work happens before the lock is released. michael@0: * (Think of cached writes, cache read-ahead, and instruction reordering michael@0: * around the CAS and store instructions.) michael@0: * michael@0: * The barriers must apply to both the compiler and the CPU. Note it is michael@0: * legal for instructions that occur before an "acquire" barrier to be michael@0: * moved down below it, and for instructions that occur after a "release" michael@0: * barrier to be moved up above it. michael@0: * michael@0: * The ARM-driven implementation we use here is short on subtlety, michael@0: * and actually requests a full barrier from the compiler and the CPU. michael@0: * The only difference between acquire and release is in whether they michael@0: * are issued before or after the atomic operation with which they michael@0: * are associated. To ease the transition to C/C++ atomic intrinsics, michael@0: * you should not rely on this, and instead assume that only the minimal michael@0: * acquire/release protection is provided. michael@0: * michael@0: * NOTE: all int32_t* values are expected to be aligned on 32-bit boundaries. michael@0: * If they are not, atomicity is not guaranteed. michael@0: */ michael@0: michael@0: /* michael@0: * Basic arithmetic and bitwise operations. These all provide a michael@0: * barrier with "release" ordering, and return the previous value. michael@0: * michael@0: * These have the same characteristics (e.g. what happens on overflow) michael@0: * as the equivalent non-atomic C operations. michael@0: */ michael@0: int32_t android_atomic_inc(volatile int32_t* addr); michael@0: int32_t android_atomic_dec(volatile int32_t* addr); michael@0: int32_t android_atomic_add(int32_t value, volatile int32_t* addr); michael@0: int32_t android_atomic_and(int32_t value, volatile int32_t* addr); michael@0: int32_t android_atomic_or(int32_t value, volatile int32_t* addr); michael@0: michael@0: /* michael@0: * Perform an atomic load with "acquire" or "release" ordering. michael@0: * michael@0: * This is only necessary if you need the memory barrier. A 32-bit read michael@0: * from a 32-bit aligned address is atomic on all supported platforms. michael@0: */ michael@0: int32_t android_atomic_acquire_load(volatile const int32_t* addr); michael@0: int32_t android_atomic_release_load(volatile const int32_t* addr); michael@0: michael@0: /* michael@0: * Perform an atomic store with "acquire" or "release" ordering. michael@0: * michael@0: * This is only necessary if you need the memory barrier. A 32-bit write michael@0: * to a 32-bit aligned address is atomic on all supported platforms. michael@0: */ michael@0: void android_atomic_acquire_store(int32_t value, volatile int32_t* addr); michael@0: void android_atomic_release_store(int32_t value, volatile int32_t* addr); michael@0: michael@0: /* michael@0: * Unconditional swap operation with release ordering. michael@0: * michael@0: * Stores the new value at *addr, and returns the previous value. michael@0: */ michael@0: int32_t android_atomic_swap(int32_t value, volatile int32_t* addr); michael@0: michael@0: /* michael@0: * Compare-and-set operation with "acquire" or "release" ordering. michael@0: * michael@0: * This returns zero if the new value was successfully stored, which will michael@0: * only happen when *addr == oldvalue. michael@0: * michael@0: * (The return value is inverted from implementations on other platforms, michael@0: * but matches the ARM ldrex/strex result.) michael@0: * michael@0: * Implementations that use the release CAS in a loop may be less efficient michael@0: * than possible, because we re-issue the memory barrier on each iteration. michael@0: */ michael@0: int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue, michael@0: volatile int32_t* addr); michael@0: int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, michael@0: volatile int32_t* addr); michael@0: michael@0: /* michael@0: * Aliases for code using an older version of this header. These are now michael@0: * deprecated and should not be used. The definitions will be removed michael@0: * in a future release. michael@0: */ michael@0: #define android_atomic_write android_atomic_release_store michael@0: #define android_atomic_cmpxchg android_atomic_release_cas michael@0: michael@0: #ifdef __cplusplus michael@0: } // extern "C" michael@0: #endif michael@0: michael@0: #endif // ANDROID_CUTILS_ATOMIC_H