blob: f1daf3bce7a0c70fa5497a4fb337da2416a56fe2 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2/* Copyright (c) 2006, Google Inc.
3 * All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004 *
Austin Schuh745610d2015-09-06 18:19:50 -07005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008 *
Austin Schuh745610d2015-09-06 18:19:50 -07009 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
Brian Silverman20350ac2021-11-17 18:19:55 -080018 *
Austin Schuh745610d2015-09-06 18:19:50 -070019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * ---
32 * Author: Sanjay Ghemawat
33 */
34
35// For atomic operations on statistics counters, see atomic_stats_counter.h.
36// For atomic operations on sequence numbers, see atomic_sequence_num.h.
37// For atomic operations on reference counts, see atomic_refcount.h.
38
39// Some fast atomic operations -- typically with machine-dependent
40// implementations. This file may need editing as Google code is
41// ported to different architectures.
42
43// The routines exported by this module are subtle. If you use them, even if
44// you get the code right, it will depend on careful reasoning about atomicity
45// and memory ordering; it will be less readable, and harder to maintain. If
46// you plan to use these routines, you should have a good reason, such as solid
47// evidence that performance would otherwise suffer, or there being no
48// alternative. You should assume only properties explicitly guaranteed by the
49// specifications in this file. You are almost certainly _not_ writing code
50// just for the x86; if you assume x86 semantics, x86 hardware bugs and
51// implementations on other archtectures will cause your code to break. If you
52// do not know what you are doing, avoid these routines, and use a Mutex.
53//
54// These following lower-level operations are typically useful only to people
55// implementing higher-level synchronization operations like spinlocks,
56// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
57// a store with appropriate memory-ordering instructions. "Acquire" operations
58// ensure that no later memory access can be reordered ahead of the operation.
59// "Release" operations ensure that no previous memory access can be reordered
60// after the operation. "Barrier" operations have both "Acquire" and "Release"
61// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
62// access.
63//
64// It is incorrect to make direct assignments to/from an atomic variable.
65// You should use one of the Load or Store routines. The NoBarrier
66// versions are provided when no barriers are needed:
67// NoBarrier_Store()
68// NoBarrier_Load()
69// Although there are currently no compiler enforcement, you are encouraged
70// to use these. Moreover, if you choose to use base::subtle::Atomic64 type,
71// you MUST use one of the Load or Store routines to get correct behavior
72// on 32-bit platforms.
73//
74// The intent is eventually to put all of these routines in namespace
75// base::subtle
76
77#ifndef THREAD_ATOMICOPS_H_
78#define THREAD_ATOMICOPS_H_
79
80#include <config.h>
81#ifdef HAVE_STDINT_H
82#include <stdint.h>
83#endif
84
85// ------------------------------------------------------------------------
86// Include the platform specific implementations of the types
87// and operations listed below. Implementations are to provide Atomic32
88// and Atomic64 operations. If there is a mismatch between intptr_t and
89// the Atomic32 or Atomic64 types for a platform, the platform-specific header
90// should define the macro, AtomicWordCastType in a clause similar to the
91// following:
92// #if ...pointers are 64 bits...
93// # define AtomicWordCastType base::subtle::Atomic64
94// #else
95// # define AtomicWordCastType Atomic32
96// #endif
97// TODO(csilvers): figure out ARCH_PIII/ARCH_K8 (perhaps via ./configure?)
98// ------------------------------------------------------------------------
99
100#include "base/arm_instruction_set_select.h"
101#define GCC_VERSION (__GNUC__ * 10000 \
102 + __GNUC_MINOR__ * 100 \
103 + __GNUC_PATCHLEVEL__)
104
Brian Silverman20350ac2021-11-17 18:19:55 -0800105#define CLANG_VERSION (__clang_major__ * 10000 \
106 + __clang_minor__ * 100 \
107 + __clang_patchlevel__)
108
Austin Schuh745610d2015-09-06 18:19:50 -0700109#if defined(TCMALLOC_PREFER_GCC_ATOMICS) && defined(__GNUC__) && GCC_VERSION >= 40700
110#include "base/atomicops-internals-gcc.h"
Brian Silverman20350ac2021-11-17 18:19:55 -0800111#elif defined(TCMALLOC_PREFER_GCC_ATOMICS) && defined(__clang__) && CLANG_VERSION >= 30400
112#include "base/atomicops-internals-gcc.h"
Austin Schuh745610d2015-09-06 18:19:50 -0700113#elif defined(__MACH__) && defined(__APPLE__)
114#include "base/atomicops-internals-macosx.h"
115#elif defined(__GNUC__) && defined(ARMV6)
116#include "base/atomicops-internals-arm-v6plus.h"
117#elif defined(ARMV3)
118#include "base/atomicops-internals-arm-generic.h"
119#elif defined(__GNUC__) && (defined(__i386) || defined(__x86_64__))
120#include "base/atomicops-internals-x86.h"
121#elif defined(_WIN32)
122#include "base/atomicops-internals-windows.h"
123#elif defined(__linux__) && defined(__PPC__)
124#include "base/atomicops-internals-linuxppc.h"
125#elif defined(__GNUC__) && defined(__mips__)
126#include "base/atomicops-internals-mips.h"
127#elif defined(__GNUC__) && GCC_VERSION >= 40700
128#include "base/atomicops-internals-gcc.h"
Brian Silverman20350ac2021-11-17 18:19:55 -0800129#elif defined(__clang__) && CLANG_VERSION >= 30400
130#include "base/atomicops-internals-gcc.h"
Austin Schuh745610d2015-09-06 18:19:50 -0700131#else
132#error You need to implement atomic operations for this architecture
133#endif
134
135// Signed type that can hold a pointer and supports the atomic ops below, as
136// well as atomic loads and stores. Instances must be naturally-aligned.
137typedef intptr_t AtomicWord;
138
139#ifdef AtomicWordCastType
140// ------------------------------------------------------------------------
141// This section is needed only when explicit type casting is required to
142// cast AtomicWord to one of the basic atomic types (Atomic64 or Atomic32).
143// It also serves to document the AtomicWord interface.
144// ------------------------------------------------------------------------
145
146namespace base {
147namespace subtle {
148
149// Atomically execute:
150// result = *ptr;
151// if (*ptr == old_value)
152// *ptr = new_value;
153// return result;
154//
155// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
156// Always return the old value of "*ptr"
157//
158// This routine implies no memory barriers.
159inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
160 AtomicWord old_value,
161 AtomicWord new_value) {
162 return NoBarrier_CompareAndSwap(
163 reinterpret_cast<volatile AtomicWordCastType*>(ptr),
164 old_value, new_value);
165}
166
167// Atomically store new_value into *ptr, returning the previous value held in
168// *ptr. This routine implies no memory barriers.
169inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
170 AtomicWord new_value) {
171 return NoBarrier_AtomicExchange(
172 reinterpret_cast<volatile AtomicWordCastType*>(ptr), new_value);
173}
174
175inline AtomicWord Acquire_AtomicExchange(volatile AtomicWord* ptr,
176 AtomicWord new_value) {
177 return Acquire_AtomicExchange(
178 reinterpret_cast<volatile AtomicWordCastType*>(ptr), new_value);
179}
180
181inline AtomicWord Release_AtomicExchange(volatile AtomicWord* ptr,
182 AtomicWord new_value) {
183 return Release_AtomicExchange(
184 reinterpret_cast<volatile AtomicWordCastType*>(ptr), new_value);
185}
186
187inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
188 AtomicWord old_value,
189 AtomicWord new_value) {
190 return base::subtle::Acquire_CompareAndSwap(
191 reinterpret_cast<volatile AtomicWordCastType*>(ptr),
192 old_value, new_value);
193}
194
195inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
196 AtomicWord old_value,
197 AtomicWord new_value) {
198 return base::subtle::Release_CompareAndSwap(
199 reinterpret_cast<volatile AtomicWordCastType*>(ptr),
200 old_value, new_value);
201}
202
203inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
204 NoBarrier_Store(
205 reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
206}
207
Austin Schuh745610d2015-09-06 18:19:50 -0700208inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
209 return base::subtle::Release_Store(
210 reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
211}
212
213inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
214 return NoBarrier_Load(
215 reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
216}
217
218inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
219 return base::subtle::Acquire_Load(
220 reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
221}
222
Austin Schuh745610d2015-09-06 18:19:50 -0700223} // namespace base::subtle
224} // namespace base
225#endif // AtomicWordCastType
226
227// ------------------------------------------------------------------------
228// Commented out type definitions and method declarations for documentation
229// of the interface provided by this module.
230// ------------------------------------------------------------------------
231
232#if 0
233
234// Signed 32-bit type that supports the atomic ops below, as well as atomic
235// loads and stores. Instances must be naturally aligned. This type differs
236// from AtomicWord in 64-bit binaries where AtomicWord is 64-bits.
237typedef int32_t Atomic32;
238
239// Corresponding operations on Atomic32
240namespace base {
241namespace subtle {
242
243// Signed 64-bit type that supports the atomic ops below, as well as atomic
244// loads and stores. Instances must be naturally aligned. This type differs
245// from AtomicWord in 32-bit binaries where AtomicWord is 32-bits.
246typedef int64_t Atomic64;
247
248Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
249 Atomic32 old_value,
250 Atomic32 new_value);
251Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
252Atomic32 Acquire_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
253Atomic32 Release_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
254Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
255 Atomic32 old_value,
256 Atomic32 new_value);
257Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
258 Atomic32 old_value,
259 Atomic32 new_value);
260void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
Austin Schuh745610d2015-09-06 18:19:50 -0700261void Release_Store(volatile Atomic32* ptr, Atomic32 value);
262Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
263Atomic32 Acquire_Load(volatile const Atomic32* ptr);
Austin Schuh745610d2015-09-06 18:19:50 -0700264
265// Corresponding operations on Atomic64
266Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
267 Atomic64 old_value,
268 Atomic64 new_value);
269Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
270Atomic64 Acquire_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
271Atomic64 Release_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
272
273Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
274 Atomic64 old_value,
275 Atomic64 new_value);
276Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
277 Atomic64 old_value,
278 Atomic64 new_value);
279void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
Austin Schuh745610d2015-09-06 18:19:50 -0700280void Release_Store(volatile Atomic64* ptr, Atomic64 value);
281Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
282Atomic64 Acquire_Load(volatile const Atomic64* ptr);
Austin Schuh745610d2015-09-06 18:19:50 -0700283} // namespace base::subtle
284} // namespace base
285
286void MemoryBarrier();
287
288#endif // 0
289
290
291// ------------------------------------------------------------------------
292// The following are to be deprecated when all uses have been changed to
293// use the base::subtle namespace.
294// ------------------------------------------------------------------------
295
296#ifdef AtomicWordCastType
297// AtomicWord versions to be deprecated
298inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
299 AtomicWord old_value,
300 AtomicWord new_value) {
301 return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value);
302}
303
304inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
305 AtomicWord old_value,
306 AtomicWord new_value) {
307 return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
308}
309
Austin Schuh745610d2015-09-06 18:19:50 -0700310inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
311 return base::subtle::Release_Store(ptr, value);
312}
313
314inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
315 return base::subtle::Acquire_Load(ptr);
316}
Austin Schuh745610d2015-09-06 18:19:50 -0700317#endif // AtomicWordCastType
318
319// 32-bit Acquire/Release operations to be deprecated.
320
321inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
322 Atomic32 old_value,
323 Atomic32 new_value) {
324 return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value);
325}
326inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
327 Atomic32 old_value,
328 Atomic32 new_value) {
329 return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
330}
Austin Schuh745610d2015-09-06 18:19:50 -0700331inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
332 return base::subtle::Release_Store(ptr, value);
333}
334inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
335 return base::subtle::Acquire_Load(ptr);
336}
Austin Schuh745610d2015-09-06 18:19:50 -0700337
338#ifdef BASE_HAS_ATOMIC64
339
340// 64-bit Acquire/Release operations to be deprecated.
341
342inline base::subtle::Atomic64 Acquire_CompareAndSwap(
343 volatile base::subtle::Atomic64* ptr,
344 base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) {
345 return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value);
346}
347inline base::subtle::Atomic64 Release_CompareAndSwap(
348 volatile base::subtle::Atomic64* ptr,
349 base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) {
350 return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
351}
Austin Schuh745610d2015-09-06 18:19:50 -0700352inline void Release_Store(
353 volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 value) {
354 return base::subtle::Release_Store(ptr, value);
355}
356inline base::subtle::Atomic64 Acquire_Load(
357 volatile const base::subtle::Atomic64* ptr) {
358 return base::subtle::Acquire_Load(ptr);
359}
Austin Schuh745610d2015-09-06 18:19:50 -0700360
361#endif // BASE_HAS_ATOMIC64
362
363#endif // THREAD_ATOMICOPS_H_