summaryrefslogtreecommitdiffstats
path: root/base/atomicops_internals_arm_gcc.h
diff options
context:
space:
mode:
authordigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-11 03:52:52 +0000
committerdigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-11 03:52:52 +0000
commit8ceb4b90f1a33141c5d8322d5771f280a5d18db3 (patch)
treeb3da71d322ca53392c2091384ba1e490411a39e7 /base/atomicops_internals_arm_gcc.h
parent5a9a71fce45b18e0fd731e60c53a5222732dd05f (diff)
downloadchromium_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.h19
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