1 // Copyright 2010 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // The routines exported by this module are subtle. If you use them, even if 6 // you get the code right, it will depend on careful reasoning about atomicity 7 // and memory ordering; it will be less readable, and harder to maintain. If 8 // you plan to use these routines, you should have a good reason, such as solid 9 // evidence that performance would otherwise suffer, or there being no 10 // alternative. You should assume only properties explicitly guaranteed by the 11 // specifications in this file. You are almost certainly _not_ writing code 12 // just for the x86; if you assume x86 semantics, x86 hardware bugs and 13 // implementations on other archtectures will cause your code to break. If you 14 // do not know what you are doing, avoid these routines, and use a Mutex. 15 // 16 // It is incorrect to make direct assignments to/from an atomic variable. 17 // You should use one of the Load or Store routines. The Relaxed versions 18 // are provided when no fences are needed: 19 // Relaxed_Store() 20 // Relaxed_Load() 21 // Although there are currently no compiler enforcement, you are encouraged 22 // to use these. 23 // 24 25 #ifndef V8_BASE_ATOMICOPS_H_ 26 #define V8_BASE_ATOMICOPS_H_ 27 28 #include <stdint.h> 29 30 // Small C++ header which defines implementation specific macros used to 31 // identify the STL implementation. 32 // - libc++: captures __config for _LIBCPP_VERSION 33 // - libstdc++: captures bits/c++config.h for __GLIBCXX__ 34 #include <cstddef> 35 36 #include "src/base/base-export.h" 37 #include "src/base/build_config.h" 38 39 #if defined(V8_OS_STARBOARD) 40 #include "starboard/atomic.h" 41 42 #if SB_API_VERSION < 10 43 #error Your version of Starboard must support SbAtomic8 in order to use V8. 44 #endif // SB_API_VERSION < 10 45 #endif // V8_OS_STARBOARD 46 47 namespace v8 { 48 namespace base { 49 50 #ifdef V8_OS_STARBOARD 51 using Atomic8 = SbAtomic8; 52 using Atomic16 = int16_t; 53 using Atomic32 = SbAtomic32; 54 #if SB_IS_64_BIT 55 using Atomic64 = SbAtomic64; 56 #endif 57 #else 58 using Atomic8 = char; 59 using Atomic16 = int16_t; 60 using Atomic32 = int32_t; 61 #if defined(V8_HOST_ARCH_64_BIT) 62 // We need to be able to go between Atomic64 and AtomicWord implicitly. This 63 // means Atomic64 and AtomicWord should be the same type on 64-bit. 64 #if defined(__ILP32__) 65 using Atomic64 = int64_t; 66 #else 67 using Atomic64 = intptr_t; 68 #endif // defined(__ILP32__) 69 #endif // defined(V8_HOST_ARCH_64_BIT) 70 #endif // V8_OS_STARBOARD 71 72 // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or 73 // Atomic64 routines below, depending on your architecture. 74 #if defined(V8_OS_STARBOARD) 75 using AtomicWord = SbAtomicPtr; 76 #else 77 using AtomicWord = intptr_t; 78 #endif 79 80 // Atomically execute: 81 // result = *ptr; 82 // if (result == old_value) 83 // *ptr = new_value; 84 // return result; 85 // 86 // I.e. replace |*ptr| with |new_value| if |*ptr| used to be |old_value|. 87 // Always return the value of |*ptr| before the operation. 88 // Acquire, Relaxed, Release correspond to standard C++ memory orders. 89 Atomic8 Relaxed_CompareAndSwap(volatile Atomic8* ptr, Atomic8 old_value, 90 Atomic8 new_value); 91 Atomic16 Relaxed_CompareAndSwap(volatile Atomic16* ptr, Atomic16 old_value, 92 Atomic16 new_value); 93 Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, 94 Atomic32 new_value); 95 Atomic32 AcquireRelease_CompareAndSwap(volatile Atomic32* ptr, 96 Atomic32 old_value, Atomic32 new_value); 97 Atomic32 Relaxed_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, 98 Atomic32 new_value); 99 Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 old_value, 100 Atomic32 new_value); 101 #ifdef V8_HOST_ARCH_64_BIT 102 Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, 103 Atomic64 new_value); 104 Atomic64 AcquireRelease_CompareAndSwap(volatile Atomic64* ptr, 105 Atomic64 old_value, Atomic64 new_value); 106 Atomic64 Relaxed_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, 107 Atomic64 new_value); 108 Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 old_value, 109 Atomic64 new_value); 110 #endif // V8_HOST_ARCH_64_BIT 111 112 // Atomically store new_value into |*ptr|, returning the previous value held in 113 // |*ptr|. 114 Atomic32 Relaxed_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); 115 #ifdef V8_HOST_ARCH_64_BIT 116 Atomic64 Relaxed_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); 117 #endif // V8_HOST_ARCH_64_BIT 118 119 // Atomically increment |*ptr| by |increment|. Returns the new value of 120 // |*ptr| with the increment applied. 121 Atomic32 Relaxed_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); 122 123 #ifdef V8_HOST_ARCH_64_BIT 124 Atomic64 Relaxed_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); 125 #endif // V8_HOST_ARCH_64_BIT 126 127 void SeqCst_MemoryFence(); 128 129 void Relaxed_Store(volatile Atomic8* ptr, Atomic8 value); 130 void Relaxed_Store(volatile Atomic16* ptr, Atomic16 value); 131 void Relaxed_Store(volatile Atomic32* ptr, Atomic32 value); 132 void Release_Store(volatile Atomic32* ptr, Atomic32 value); 133 #ifdef V8_HOST_ARCH_64_BIT 134 void Relaxed_Store(volatile Atomic64* ptr, Atomic64 value); 135 void Release_Store(volatile Atomic64* ptr, Atomic64 value); 136 #endif // V8_HOST_ARCH_64_BIT 137 138 Atomic8 Relaxed_Load(volatile const Atomic8* ptr); 139 Atomic16 Relaxed_Load(volatile const Atomic16* ptr); 140 Atomic32 Relaxed_Load(volatile const Atomic32* ptr); 141 Atomic32 Acquire_Load(volatile const Atomic32* ptr); 142 #ifdef V8_HOST_ARCH_64_BIT 143 Atomic64 Relaxed_Load(volatile const Atomic64* ptr); 144 Atomic64 Acquire_Load(volatile const Atomic64* ptr); 145 #endif // V8_HOST_ARCH_64_BIT 146 147 } // namespace base 148 } // namespace v8 149 150 #if defined(V8_OS_WIN) || defined(V8_OS_STARBOARD) 151 #include "src/base/atomicops_internals_std.h" 152 #else 153 // TODO(ulan): Switch to std version after performance regression with Wheezy 154 // sysroot is no longer relevant. Debian Wheezy LTS ends on 31st of May 2018. 155 #include "src/base/atomicops_internals_portable.h" 156 #endif 157 158 // On some platforms we need additional declarations to make 159 // AtomicWord compatible with our other Atomic* types. 160 #if defined(V8_OS_MACOSX) || defined(V8_OS_OPENBSD) || defined(V8_OS_AIX) 161 #include "src/base/atomicops_internals_atomicword_compat.h" 162 #endif 163 164 #endif // V8_BASE_ATOMICOPS_H_ 165