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