michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=8 et : michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // This file is an internal atomic implementation, use michael@0: // base/atomicops.h instead. michael@0: // michael@0: // This is a very slow fallback implementation of atomic operations michael@0: // that uses a mutex instead of atomic instructions. michael@0: // michael@0: // (NB: a small "optimization" here would be using a spinlock instead michael@0: // of a blocking mutex, but it's probably not worth the time.) michael@0: michael@0: #ifndef base_atomicops_internals_mutex_h michael@0: #define base_atomicops_internals_mutex_h michael@0: michael@0: #include "base/lock.h" michael@0: michael@0: namespace base { michael@0: namespace subtle { michael@0: michael@0: extern Lock gAtomicsMutex; michael@0: michael@0: template michael@0: T Locked_CAS(volatile T* ptr, T old_value, T new_value) { michael@0: AutoLock _(gAtomicsMutex); michael@0: michael@0: T current_value = *ptr; michael@0: if (current_value == old_value) michael@0: *ptr = new_value; michael@0: michael@0: return current_value; michael@0: } michael@0: michael@0: template michael@0: T Locked_AtomicExchange(volatile T* ptr, T new_value) { michael@0: AutoLock _(gAtomicsMutex); michael@0: michael@0: T current_value = *ptr; michael@0: *ptr = new_value; michael@0: return current_value; michael@0: } michael@0: michael@0: template michael@0: T Locked_AtomicIncrement(volatile T* ptr, T increment) { michael@0: AutoLock _(gAtomicsMutex); michael@0: return *ptr += increment; michael@0: } michael@0: michael@0: template michael@0: void Locked_Store(volatile T* ptr, T value) { michael@0: AutoLock _(gAtomicsMutex); michael@0: *ptr = value; michael@0: } michael@0: michael@0: template michael@0: T Locked_Load(volatile const T* ptr) { michael@0: AutoLock _(gAtomicsMutex); michael@0: return *ptr; michael@0: } michael@0: michael@0: inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, michael@0: Atomic32 old_value, michael@0: Atomic32 new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, michael@0: Atomic32 new_value) { michael@0: return Locked_AtomicExchange(ptr, new_value); michael@0: } michael@0: michael@0: inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, michael@0: Atomic32 increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, michael@0: Atomic32 increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, michael@0: Atomic32 old_value, michael@0: Atomic32 new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, michael@0: Atomic32 old_value, michael@0: Atomic32 new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline void MemoryBarrier() { michael@0: AutoLock _(gAtomicsMutex); michael@0: // lock/unlock work as a barrier here michael@0: } michael@0: michael@0: inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) { michael@0: return NoBarrier_Load(ptr); michael@0: } michael@0: michael@0: inline Atomic32 Release_Load(volatile const Atomic32* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: #ifdef ARCH_CPU_64_BITS michael@0: michael@0: inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, michael@0: Atomic64 old_value, michael@0: Atomic64 new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, michael@0: Atomic64 new_value) { michael@0: return Locked_AtomicExchange(ptr, new_value); michael@0: } michael@0: michael@0: inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, michael@0: Atomic64 increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, michael@0: Atomic64 increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, michael@0: Atomic64 old_value, michael@0: Atomic64 new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: inline Atomic64 Release_Load(volatile const Atomic64* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: #endif // ARCH_CPU_64_BITS michael@0: michael@0: #ifdef OS_MACOSX michael@0: // From atomicops_internals_x86_macosx.h: michael@0: // michael@0: // MacOS uses long for intptr_t, AtomicWord and Atomic32 are always michael@0: // different on the Mac, even when they are the same size. We need michael@0: // to explicitly cast from AtomicWord to Atomic32/64 to implement michael@0: // the AtomicWord interface. michael@0: michael@0: inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, michael@0: AtomicWord old_value, michael@0: AtomicWord new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, michael@0: AtomicWord new_value) { michael@0: return Locked_AtomicExchange(ptr, new_value); michael@0: } michael@0: michael@0: inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, michael@0: AtomicWord increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr, michael@0: AtomicWord increment) { michael@0: return Locked_AtomicIncrement(ptr, increment); michael@0: } michael@0: michael@0: inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, michael@0: AtomicWord old_value, michael@0: AtomicWord new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, michael@0: AtomicWord old_value, michael@0: AtomicWord new_value) { michael@0: return Locked_CAS(ptr, old_value, new_value); michael@0: } michael@0: michael@0: inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { michael@0: return Locked_Store(ptr, value); michael@0: } michael@0: michael@0: inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: inline AtomicWord Release_Load(volatile const AtomicWord* ptr) { michael@0: return Locked_Load(ptr); michael@0: } michael@0: michael@0: #endif // OS_MACOSX michael@0: michael@0: } // namespace subtle michael@0: } // namespace base michael@0: michael@0: #endif // base_atomicops_internals_mutex_h