diff options
author | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-11 03:52:52 +0000 |
---|---|---|
committer | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-11 03:52:52 +0000 |
commit | 8ceb4b90f1a33141c5d8322d5771f280a5d18db3 (patch) | |
tree | b3da71d322ca53392c2091384ba1e490411a39e7 /base/atomicops_internals_arm_gcc.h | |
parent | 5a9a71fce45b18e0fd731e60c53a5222732dd05f (diff) | |
download | chromium_src-8ceb4b90f1a33141c5d8322d5771f280a5d18db3.zip chromium_src-8ceb4b90f1a33141c5d8322d5771f280a5d18db3.tar.gz chromium_src-8ceb4b90f1a33141c5d8322d5771f280a5d18db3.tar.bz2 |
Refine atomic operations for Linux/ARM.
This patch comes from recent discussions from the following
review link:
https://chromiumcodereview.appspot.com/16109010/
In a nutshell:
- Using the "cmp" instruction, instead of "teq" is
better for recent ARM CPUs.
- Fix a tiny typo.
- Fix the ARMv5 implementation of Release_CompareAndSwap()
since the old one could return without performing any
memory barrier when prev_value != old_value.
It's not clear whether the old behaviour is desirable
because client code could naively assume the function
always perform a release operation, even in case of
failure.
BUG=234215
Review URL: https://chromiumcodereview.appspot.com/18984012
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211013 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/atomicops_internals_arm_gcc.h')
-rw-r--r-- | base/atomicops_internals_arm_gcc.h | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h index 9a6606e..9f4fe2e 100644 --- a/base/atomicops_internals_arm_gcc.h +++ b/base/atomicops_internals_arm_gcc.h @@ -70,7 +70,7 @@ inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, // reloop = STREX(ptr, new_value) __asm__ __volatile__(" ldrex %0, [%3]\n" " mov %1, #0\n" - " teq %0, %4\n" + " cmp %0, %4\n" #ifdef __thumb2__ " it eq\n" #endif @@ -135,7 +135,7 @@ inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, int reloop; do { // old_value = LDREX(ptr) - // fail = STREX(ptr, new_value) + // reloop = STREX(ptr, new_value) __asm__ __volatile__(" ldrex %0, [%3]\n" " strex %1, %4, [%3]\n" : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr) @@ -232,10 +232,17 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, Atomic32 new_value) { - // Use NoBarrier_CompareAndSwap(), because its implementation - // ensures that all stores happen through the kernel helper - // which always implement a full barrier. - return NoBarrier_CompareAndSwap(ptr, old_value, new_value); + // This could be implemented as: + // MemoryBarrier(); + // return NoBarrier_CompareAndSwap(); + // + // But would use 3 barriers per succesful CAS. To save performance, + // use Acquire_CompareAndSwap(). Its implementation guarantees that: + // - A succesful swap uses only 2 barriers (in the kernel helper). + // - An early return due to (prev_value != old_value) performs + // a memory barrier with no store, which is equivalent to the + // generic implementation above. + return Acquire_CompareAndSwap(ptr, old_value, new_value); } #else |