1 // Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012 2 // Google Inc. All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the name Chromium Embedded 15 // Framework nor the names of its contributors may be used to endorse 16 // or promote products derived from this software without specific prior 17 // written permission. 18 // 19 // 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 // For atomic operations on reference counts, see cef_atomic_ref_count.h. 32 33 // The routines exported by this module are subtle. If you use them, even if 34 // you get the code right, it will depend on careful reasoning about atomicity 35 // and memory ordering; it will be less readable, and harder to maintain. If 36 // you plan to use these routines, you should have a good reason, such as solid 37 // evidence that performance would otherwise suffer, or there being no 38 // alternative. You should assume only properties explicitly guaranteed by the 39 // specifications in this file. You are almost certainly _not_ writing code 40 // just for the x86; if you assume x86 semantics, x86 hardware bugs and 41 // implementations on other archtectures will cause your code to break. If you 42 // do not know what you are doing, avoid these routines, and use a Mutex. 43 // 44 // It is incorrect to make direct assignments to/from an atomic variable. 45 // You should use one of the Load or Store routines. The NoBarrier 46 // versions are provided when no barriers are needed: 47 // NoBarrier_Store() 48 // NoBarrier_Load() 49 // Although there are currently no compiler enforcement, you are encouraged 50 // to use these. 51 // 52 53 #ifndef CEF_INCLUDE_BASE_CEF_ATOMICOPS_H_ 54 #define CEF_INCLUDE_BASE_CEF_ATOMICOPS_H_ 55 #pragma once 56 57 #if defined(BASE_ATOMICOPS_H_) 58 // Do nothing if the Chromium header has already been included. 59 // This can happen in cases where Chromium code is used directly by the 60 // client application. When using Chromium code directly always include 61 // the Chromium header first to avoid type conflicts. 62 #elif defined(USING_CHROMIUM_INCLUDES) 63 // When building CEF include the Chromium header directly. 64 #include "base/atomicops.h" 65 #else // !USING_CHROMIUM_INCLUDES 66 // The following is substantially similar to the Chromium implementation. 67 // If the Chromium implementation diverges the below implementation should be 68 // updated to match. 69 70 #include <stdint.h> 71 72 #include "include/base/cef_build.h" 73 74 #if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) 75 // windows.h #defines this (only on x64). This causes problems because the 76 // public API also uses MemoryBarrier at the public name for this fence. So, on 77 // X64, undef it, and call its documented 78 // (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx) 79 // implementation directly. 80 #undef MemoryBarrier 81 #endif 82 83 namespace base { 84 namespace subtle { 85 86 typedef int32_t Atomic32; 87 #ifdef ARCH_CPU_64_BITS 88 // We need to be able to go between Atomic64 and AtomicWord implicitly. This 89 // means Atomic64 and AtomicWord should be the same type on 64-bit. 90 #if defined(__ILP32__) || defined(OS_NACL) 91 // NaCl's intptr_t is not actually 64-bits on 64-bit! 92 // http://code.google.com/p/nativeclient/issues/detail?id=1162 93 typedef int64_t Atomic64; 94 #else 95 typedef intptr_t Atomic64; 96 #endif 97 #endif 98 99 // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or 100 // Atomic64 routines below, depending on your architecture. 101 typedef intptr_t AtomicWord; 102 103 // Atomically execute: 104 // result = *ptr; 105 // if (*ptr == old_value) 106 // *ptr = new_value; 107 // return result; 108 // 109 // I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". 110 // Always return the old value of "*ptr" 111 // 112 // This routine implies no memory barriers. 113 Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr, 114 Atomic32 old_value, 115 Atomic32 new_value); 116 117 // Atomically store new_value into *ptr, returning the previous value held in 118 // *ptr. This routine implies no memory barriers. 119 Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value); 120 121 // Atomically increment *ptr by "increment". Returns the new value of 122 // *ptr with the increment applied. This routine implies no memory barriers. 123 Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); 124 125 Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment); 126 127 // These following lower-level operations are typically useful only to people 128 // implementing higher-level synchronization operations like spinlocks, 129 // mutexes, and condition-variables. They combine CompareAndSwap(), a load, or 130 // a store with appropriate memory-ordering instructions. "Acquire" operations 131 // ensure that no later memory access can be reordered ahead of the operation. 132 // "Release" operations ensure that no previous memory access can be reordered 133 // after the operation. "Barrier" operations have both "Acquire" and "Release" 134 // semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory 135 // access. 136 Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, 137 Atomic32 old_value, 138 Atomic32 new_value); 139 Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, 140 Atomic32 old_value, 141 Atomic32 new_value); 142 143 void MemoryBarrier(); 144 void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); 145 void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); 146 void Release_Store(volatile Atomic32* ptr, Atomic32 value); 147 148 Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); 149 Atomic32 Acquire_Load(volatile const Atomic32* ptr); 150 Atomic32 Release_Load(volatile const Atomic32* ptr); 151 152 // 64-bit atomic operations (only available on 64-bit processors). 153 #ifdef ARCH_CPU_64_BITS 154 Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, 155 Atomic64 old_value, 156 Atomic64 new_value); 157 Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value); 158 Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); 159 Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment); 160 161 Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, 162 Atomic64 old_value, 163 Atomic64 new_value); 164 Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, 165 Atomic64 old_value, 166 Atomic64 new_value); 167 void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); 168 void Acquire_Store(volatile Atomic64* ptr, Atomic64 value); 169 void Release_Store(volatile Atomic64* ptr, Atomic64 value); 170 Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); 171 Atomic64 Acquire_Load(volatile const Atomic64* ptr); 172 Atomic64 Release_Load(volatile const Atomic64* ptr); 173 #endif // ARCH_CPU_64_BITS 174 175 } // namespace subtle 176 } // namespace base 177 178 // Include our platform specific implementation. 179 #if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) 180 #include "include/base/internal/cef_atomicops_x86_msvc.h" 181 #elif defined(OS_WIN) && (defined(__ARM_ARCH_ISA_A64) || defined(_M_ARM64)) 182 #include "include/base/internal/cef_atomicops_arm64_msvc.h" 183 #elif defined(OS_MAC) 184 #include "include/base/internal/cef_atomicops_mac.h" 185 #elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY) 186 #include "include/base/internal/cef_atomicops_x86_gcc.h" 187 #elif defined(COMPILER_GCC) && defined(__ARM_ARCH_ISA_A64) 188 #include "include/base/internal/cef_atomicops_arm64_gcc.h" 189 #elif defined(COMPILER_GCC) && defined(__ARM_ARCH) 190 #include "include/base/internal/cef_atomicops_arm_gcc.h" 191 #else 192 #error "Atomic operations are not supported on your platform" 193 #endif 194 195 // On some platforms we need additional declarations to make 196 // AtomicWord compatible with our other Atomic* types. 197 #if defined(OS_MAC) || defined(OS_OPENBSD) 198 #include "include/base/internal/cef_atomicops_atomicword_compat.h" 199 #endif 200 201 #endif // !USING_CHROMIUM_INCLUDES 202 203 #endif // CEF_INCLUDE_BASE_CEF_ATOMICOPS_H_ 204