1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For atomic operations on reference counts, see atomic_refcount.h. 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// For atomic operations on sequence numbers, see atomic_sequence_num.h. 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// The routines exported by this module are subtle. If you use them, even if 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// you get the code right, it will depend on careful reasoning about atomicity 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// and memory ordering; it will be less readable, and harder to maintain. If 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// you plan to use these routines, you should have a good reason, such as solid 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// evidence that performance would otherwise suffer, or there being no 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// alternative. You should assume only properties explicitly guaranteed by the 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// specifications in this file. You are almost certainly _not_ writing code 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// just for the x86; if you assume x86 semantics, x86 hardware bugs and 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// implementations on other archtectures will cause your code to break. If you 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// do not know what you are doing, avoid these routines, and use a Mutex. 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// It is incorrect to make direct assignments to/from an atomic variable. 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// You should use one of the Load or Store routines. The NoBarrier 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// versions are provided when no barriers are needed: 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// NoBarrier_Store() 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// NoBarrier_Load() 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Although there are currently no compiler enforcement, you are encouraged 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// to use these. 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifndef BASE_ATOMICOPS_H_ 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define BASE_ATOMICOPS_H_ 303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/basictypes.h" 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "build/build_config.h" 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base { 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace subtle { 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Bug 1308991. We need this for /Wp64, to mark it safe for AtomicWord casting. 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifndef OS_WIN 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define __w64 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef __w64 int32 Atomic32; 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef ARCH_CPU_64_BITS 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We need to be able to go between Atomic64 and AtomicWord implicitly. This 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// means Atomic64 and AtomicWord should be the same type on 64-bit. 4621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#if defined(OS_NACL) 4721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// NaCl's intptr_t is not actually 64-bits on 64-bit! 4821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// http://code.google.com/p/nativeclient/issues/detail?id=1162 4921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsentypedef int64_t Atomic64; 5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#else 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef intptr_t Atomic64; 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#endif 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Atomic64 routines below, depending on your architecture. 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttypedef intptr_t AtomicWord; 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Atomically execute: 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// result = *ptr; 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// if (*ptr == old_value) 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// *ptr = new_value; 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// return result; 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Always return the old value of "*ptr" 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This routine implies no memory barriers. 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 old_value, 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 new_value); 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Atomically store new_value into *ptr, returning the previous value held in 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// *ptr. This routine implies no memory barriers. 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Atomically increment *ptr by "increment". Returns the new value of 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// *ptr with the increment applied. This routine implies no memory barriers. 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 increment); 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// These following lower-level operations are typically useful only to people 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// implementing higher-level synchronization operations like spinlocks, 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// a store with appropriate memory-ordering instructions. "Acquire" operations 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ensure that no later memory access can be reordered ahead of the operation. 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// "Release" operations ensure that no previous memory access can be reordered 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// after the operation. "Barrier" operations have both "Acquire" and "Release" 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// access. 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 old_value, 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 new_value); 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 Release_CompareAndSwap(volatile Atomic32* ptr, 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 old_value, 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic32 new_value); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid MemoryBarrier(); 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid Acquire_Store(volatile Atomic32* ptr, Atomic32 value); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid Release_Store(volatile Atomic32* ptr, Atomic32 value); 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 NoBarrier_Load(volatile const Atomic32* ptr); 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 Acquire_Load(volatile const Atomic32* ptr); 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic32 Release_Load(volatile const Atomic32* ptr); 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 64-bit atomic operations (only available on 64-bit processors). 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifdef ARCH_CPU_64_BITS 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 old_value, 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 new_value); 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 old_value, 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 new_value); 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 Release_CompareAndSwap(volatile Atomic64* ptr, 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 old_value, 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Atomic64 new_value); 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid Acquire_Store(volatile Atomic64* ptr, Atomic64 value); 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid Release_Store(volatile Atomic64* ptr, Atomic64 value); 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 NoBarrier_Load(volatile const Atomic64* ptr); 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 Acquire_Load(volatile const Atomic64* ptr); 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottAtomic64 Release_Load(volatile const Atomic64* ptr); 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif // ARCH_CPU_64_BITS 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace base::subtle 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace base 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Include our platform specific implementation. 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/atomicops_internals_x86_msvc.h" 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY) 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/atomicops_internals_x86_macosx.h" 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/atomicops_internals_x86_gcc.h" 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY) 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/atomicops_internals_arm_gcc.h" 1447dd039766e8bea164f5e14cb9ab26c59d3b9a5bdPaul Lind#elif defined(COMPILER_GCC) && defined(ARCH_CPU_MIPS_FAMILY) 1457dd039766e8bea164f5e14cb9ab26c59d3b9a5bdPaul Lind#include "base/atomicops_internals_mips_gcc.h" 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#else 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#error "Atomic operations are not supported on your platform" 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// On some platforms we need additional declarations to make 151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// AtomicWord compatible with our other Atomic* types. 152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_MACOSX) || defined(OS_OPENBSD) 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/atomicops_internals_atomicword_compat.h" 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif // BASE_ATOMICOPS_H_ 157