1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/Atomics.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1062 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Implements (almost always) lock-free atomic operations. The operations here 1.12 + * are a subset of that which can be found in C++11's <atomic> header, with a 1.13 + * different API to enforce consistent memory ordering constraints. 1.14 + * 1.15 + * Anyone caught using |volatile| for inter-thread memory safety needs to be 1.16 + * sent a copy of this header and the C++11 standard. 1.17 + */ 1.18 + 1.19 +#ifndef mozilla_Atomics_h 1.20 +#define mozilla_Atomics_h 1.21 + 1.22 +#include "mozilla/Assertions.h" 1.23 +#include "mozilla/Attributes.h" 1.24 +#include "mozilla/Compiler.h" 1.25 +#include "mozilla/TypeTraits.h" 1.26 + 1.27 +#include <stdint.h> 1.28 + 1.29 +/* 1.30 + * Our minimum deployment target on clang/OS X is OS X 10.6, whose SDK 1.31 + * does not have <atomic>. So be sure to check for <atomic> support 1.32 + * along with C++0x support. 1.33 + */ 1.34 +#if defined(__clang__) || defined(__GNUC__) 1.35 + /* 1.36 + * Clang doesn't like <atomic> from libstdc++ before 4.7 due to the 1.37 + * loose typing of the atomic builtins. GCC 4.5 and 4.6 lacks inline 1.38 + * definitions for unspecialized std::atomic and causes linking errors. 1.39 + * Therefore, we require at least 4.7.0 for using libstdc++. 1.40 + */ 1.41 +# if MOZ_USING_LIBSTDCXX && MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 7, 0) 1.42 +# define MOZ_HAVE_CXX11_ATOMICS 1.43 +# elif MOZ_USING_LIBCXX 1.44 +# define MOZ_HAVE_CXX11_ATOMICS 1.45 +# endif 1.46 +#elif defined(_MSC_VER) && _MSC_VER >= 1700 1.47 +# if defined(DEBUG) 1.48 + /* 1.49 + * Provide our own failure code since we're having trouble linking to 1.50 + * std::_Debug_message (bug 982310). 1.51 + */ 1.52 +# define _INVALID_MEMORY_ORDER MOZ_CRASH("Invalid memory order") 1.53 +# endif 1.54 +# define MOZ_HAVE_CXX11_ATOMICS 1.55 +#endif 1.56 + 1.57 +namespace mozilla { 1.58 + 1.59 +/** 1.60 + * An enum of memory ordering possibilities for atomics. 1.61 + * 1.62 + * Memory ordering is the observable state of distinct values in memory. 1.63 + * (It's a separate concept from atomicity, which concerns whether an 1.64 + * operation can ever be observed in an intermediate state. Don't 1.65 + * conflate the two!) Given a sequence of operations in source code on 1.66 + * memory, it is *not* always the case that, at all times and on all 1.67 + * cores, those operations will appear to have occurred in that exact 1.68 + * sequence. First, the compiler might reorder that sequence, if it 1.69 + * thinks another ordering will be more efficient. Second, the CPU may 1.70 + * not expose so consistent a view of memory. CPUs will often perform 1.71 + * their own instruction reordering, above and beyond that performed by 1.72 + * the compiler. And each core has its own memory caches, and accesses 1.73 + * (reads and writes both) to "memory" may only resolve to out-of-date 1.74 + * cache entries -- not to the "most recently" performed operation in 1.75 + * some global sense. Any access to a value that may be used by 1.76 + * multiple threads, potentially across multiple cores, must therefore 1.77 + * have a memory ordering imposed on it, for all code on all 1.78 + * threads/cores to have a sufficiently coherent worldview. 1.79 + * 1.80 + * http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and 1.81 + * http://en.cppreference.com/w/cpp/atomic/memory_order go into more 1.82 + * detail on all this, including examples of how each mode works. 1.83 + * 1.84 + * Note that for simplicity and practicality, not all of the modes in 1.85 + * C++11 are supported. The missing C++11 modes are either subsumed by 1.86 + * the modes we provide below, or not relevant for the CPUs we support 1.87 + * in Gecko. These three modes are confusing enough as it is! 1.88 + */ 1.89 +enum MemoryOrdering { 1.90 + /* 1.91 + * Relaxed ordering is the simplest memory ordering: none at all. 1.92 + * When the result of a write is observed, nothing may be inferred 1.93 + * about other memory. Writes ostensibly performed "before" on the 1.94 + * writing thread may not yet be visible. Writes performed "after" on 1.95 + * the writing thread may already be visible, if the compiler or CPU 1.96 + * reordered them. (The latter can happen if reads and/or writes get 1.97 + * held up in per-processor caches.) Relaxed ordering means 1.98 + * operations can always use cached values (as long as the actual 1.99 + * updates to atomic values actually occur, correctly, eventually), so 1.100 + * it's usually the fastest sort of atomic access. For this reason, 1.101 + * *it's also the most dangerous kind of access*. 1.102 + * 1.103 + * Relaxed ordering is good for things like process-wide statistics 1.104 + * counters that don't need to be consistent with anything else, so 1.105 + * long as updates themselves are atomic. (And so long as any 1.106 + * observations of that value can tolerate being out-of-date -- if you 1.107 + * need some sort of up-to-date value, you need some sort of other 1.108 + * synchronizing operation.) It's *not* good for locks, mutexes, 1.109 + * reference counts, etc. that mediate access to other memory, or must 1.110 + * be observably consistent with other memory. 1.111 + * 1.112 + * x86 architectures don't take advantage of the optimization 1.113 + * opportunities that relaxed ordering permits. Thus it's possible 1.114 + * that using relaxed ordering will "work" on x86 but fail elsewhere 1.115 + * (ARM, say, which *does* implement non-sequentially-consistent 1.116 + * relaxed ordering semantics). Be extra-careful using relaxed 1.117 + * ordering if you can't easily test non-x86 architectures! 1.118 + */ 1.119 + Relaxed, 1.120 + /* 1.121 + * When an atomic value is updated with ReleaseAcquire ordering, and 1.122 + * that new value is observed with ReleaseAcquire ordering, prior 1.123 + * writes (atomic or not) are also observable. What ReleaseAcquire 1.124 + * *doesn't* give you is any observable ordering guarantees for 1.125 + * ReleaseAcquire-ordered operations on different objects. For 1.126 + * example, if there are two cores that each perform ReleaseAcquire 1.127 + * operations on separate objects, each core may or may not observe 1.128 + * the operations made by the other core. The only way the cores can 1.129 + * be synchronized with ReleaseAcquire is if they both 1.130 + * ReleaseAcquire-access the same object. This implies that you can't 1.131 + * necessarily describe some global total ordering of ReleaseAcquire 1.132 + * operations. 1.133 + * 1.134 + * ReleaseAcquire ordering is good for (as the name implies) atomic 1.135 + * operations on values controlling ownership of things: reference 1.136 + * counts, mutexes, and the like. However, if you are thinking about 1.137 + * using these to implement your own locks or mutexes, you should take 1.138 + * a good, hard look at actual lock or mutex primitives first. 1.139 + */ 1.140 + ReleaseAcquire, 1.141 + /* 1.142 + * When an atomic value is updated with SequentiallyConsistent 1.143 + * ordering, all writes observable when the update is observed, just 1.144 + * as with ReleaseAcquire ordering. But, furthermore, a global total 1.145 + * ordering of SequentiallyConsistent operations *can* be described. 1.146 + * For example, if two cores perform SequentiallyConsistent operations 1.147 + * on separate objects, one core will observably perform its update 1.148 + * (and all previous operations will have completed), then the other 1.149 + * core will observably perform its update (and all previous 1.150 + * operations will have completed). (Although those previous 1.151 + * operations aren't themselves ordered -- they could be intermixed, 1.152 + * or ordered if they occur on atomic values with ordering 1.153 + * requirements.) SequentiallyConsistent is the *simplest and safest* 1.154 + * ordering of atomic operations -- it's always as if one operation 1.155 + * happens, then another, then another, in some order -- and every 1.156 + * core observes updates to happen in that single order. Because it 1.157 + * has the most synchronization requirements, operations ordered this 1.158 + * way also tend to be slowest. 1.159 + * 1.160 + * SequentiallyConsistent ordering can be desirable when multiple 1.161 + * threads observe objects, and they all have to agree on the 1.162 + * observable order of changes to them. People expect 1.163 + * SequentiallyConsistent ordering, even if they shouldn't, when 1.164 + * writing code, atomic or otherwise. SequentiallyConsistent is also 1.165 + * the ordering of choice when designing lockless data structures. If 1.166 + * you don't know what order to use, use this one. 1.167 + */ 1.168 + SequentiallyConsistent, 1.169 +}; 1.170 + 1.171 +} // namespace mozilla 1.172 + 1.173 +// Build up the underlying intrinsics. 1.174 +#ifdef MOZ_HAVE_CXX11_ATOMICS 1.175 + 1.176 +# include <atomic> 1.177 + 1.178 +namespace mozilla { 1.179 +namespace detail { 1.180 + 1.181 +/* 1.182 + * We provide CompareExchangeFailureOrder to work around a bug in some 1.183 + * versions of GCC's <atomic> header. See bug 898491. 1.184 + */ 1.185 +template<MemoryOrdering Order> struct AtomicOrderConstraints; 1.186 + 1.187 +template<> 1.188 +struct AtomicOrderConstraints<Relaxed> 1.189 +{ 1.190 + static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed; 1.191 + static const std::memory_order LoadOrder = std::memory_order_relaxed; 1.192 + static const std::memory_order StoreOrder = std::memory_order_relaxed; 1.193 + static const std::memory_order CompareExchangeFailureOrder = 1.194 + std::memory_order_relaxed; 1.195 +}; 1.196 + 1.197 +template<> 1.198 +struct AtomicOrderConstraints<ReleaseAcquire> 1.199 +{ 1.200 + static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel; 1.201 + static const std::memory_order LoadOrder = std::memory_order_acquire; 1.202 + static const std::memory_order StoreOrder = std::memory_order_release; 1.203 + static const std::memory_order CompareExchangeFailureOrder = 1.204 + std::memory_order_acquire; 1.205 +}; 1.206 + 1.207 +template<> 1.208 +struct AtomicOrderConstraints<SequentiallyConsistent> 1.209 +{ 1.210 + static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst; 1.211 + static const std::memory_order LoadOrder = std::memory_order_seq_cst; 1.212 + static const std::memory_order StoreOrder = std::memory_order_seq_cst; 1.213 + static const std::memory_order CompareExchangeFailureOrder = 1.214 + std::memory_order_seq_cst; 1.215 +}; 1.216 + 1.217 +template<typename T, MemoryOrdering Order> 1.218 +struct IntrinsicBase 1.219 +{ 1.220 + typedef std::atomic<T> ValueType; 1.221 + typedef AtomicOrderConstraints<Order> OrderedOp; 1.222 +}; 1.223 + 1.224 +template<typename T, MemoryOrdering Order> 1.225 +struct IntrinsicMemoryOps : public IntrinsicBase<T, Order> 1.226 +{ 1.227 + typedef IntrinsicBase<T, Order> Base; 1.228 + static T load(const typename Base::ValueType& ptr) { 1.229 + return ptr.load(Base::OrderedOp::LoadOrder); 1.230 + } 1.231 + static void store(typename Base::ValueType& ptr, T val) { 1.232 + ptr.store(val, Base::OrderedOp::StoreOrder); 1.233 + } 1.234 + static T exchange(typename Base::ValueType& ptr, T val) { 1.235 + return ptr.exchange(val, Base::OrderedOp::AtomicRMWOrder); 1.236 + } 1.237 + static bool compareExchange(typename Base::ValueType& ptr, T oldVal, T newVal) { 1.238 + return ptr.compare_exchange_strong(oldVal, newVal, 1.239 + Base::OrderedOp::AtomicRMWOrder, 1.240 + Base::OrderedOp::CompareExchangeFailureOrder); 1.241 + } 1.242 +}; 1.243 + 1.244 +template<typename T, MemoryOrdering Order> 1.245 +struct IntrinsicAddSub : public IntrinsicBase<T, Order> 1.246 +{ 1.247 + typedef IntrinsicBase<T, Order> Base; 1.248 + static T add(typename Base::ValueType& ptr, T val) { 1.249 + return ptr.fetch_add(val, Base::OrderedOp::AtomicRMWOrder); 1.250 + } 1.251 + static T sub(typename Base::ValueType& ptr, T val) { 1.252 + return ptr.fetch_sub(val, Base::OrderedOp::AtomicRMWOrder); 1.253 + } 1.254 +}; 1.255 + 1.256 +template<typename T, MemoryOrdering Order> 1.257 +struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order> 1.258 +{ 1.259 + typedef IntrinsicBase<T*, Order> Base; 1.260 + static T* add(typename Base::ValueType& ptr, ptrdiff_t val) { 1.261 + return ptr.fetch_add(fixupAddend(val), Base::OrderedOp::AtomicRMWOrder); 1.262 + } 1.263 + static T* sub(typename Base::ValueType& ptr, ptrdiff_t val) { 1.264 + return ptr.fetch_sub(fixupAddend(val), Base::OrderedOp::AtomicRMWOrder); 1.265 + } 1.266 + private: 1.267 + /* 1.268 + * GCC 4.6's <atomic> header has a bug where adding X to an 1.269 + * atomic<T*> is not the same as adding X to a T*. Hence the need 1.270 + * for this function to provide the correct addend. 1.271 + */ 1.272 + static ptrdiff_t fixupAddend(ptrdiff_t val) { 1.273 +#if defined(__clang__) || defined(_MSC_VER) 1.274 + return val; 1.275 +#elif defined(__GNUC__) && MOZ_GCC_VERSION_AT_LEAST(4, 6, 0) && \ 1.276 + !MOZ_GCC_VERSION_AT_LEAST(4, 7, 0) 1.277 + return val * sizeof(T); 1.278 +#else 1.279 + return val; 1.280 +#endif 1.281 + } 1.282 +}; 1.283 + 1.284 +template<typename T, MemoryOrdering Order> 1.285 +struct IntrinsicIncDec : public IntrinsicAddSub<T, Order> 1.286 +{ 1.287 + typedef IntrinsicBase<T, Order> Base; 1.288 + static T inc(typename Base::ValueType& ptr) { 1.289 + return IntrinsicAddSub<T, Order>::add(ptr, 1); 1.290 + } 1.291 + static T dec(typename Base::ValueType& ptr) { 1.292 + return IntrinsicAddSub<T, Order>::sub(ptr, 1); 1.293 + } 1.294 +}; 1.295 + 1.296 +template<typename T, MemoryOrdering Order> 1.297 +struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>, 1.298 + public IntrinsicIncDec<T, Order> 1.299 +{ 1.300 + typedef IntrinsicBase<T, Order> Base; 1.301 + static T or_(typename Base::ValueType& ptr, T val) { 1.302 + return ptr.fetch_or(val, Base::OrderedOp::AtomicRMWOrder); 1.303 + } 1.304 + static T xor_(typename Base::ValueType& ptr, T val) { 1.305 + return ptr.fetch_xor(val, Base::OrderedOp::AtomicRMWOrder); 1.306 + } 1.307 + static T and_(typename Base::ValueType& ptr, T val) { 1.308 + return ptr.fetch_and(val, Base::OrderedOp::AtomicRMWOrder); 1.309 + } 1.310 +}; 1.311 + 1.312 +template<typename T, MemoryOrdering Order> 1.313 +struct AtomicIntrinsics<T*, Order> 1.314 + : public IntrinsicMemoryOps<T*, Order>, public IntrinsicIncDec<T*, Order> 1.315 +{ 1.316 +}; 1.317 + 1.318 +} // namespace detail 1.319 +} // namespace mozilla 1.320 + 1.321 +#elif defined(__GNUC__) 1.322 + 1.323 +namespace mozilla { 1.324 +namespace detail { 1.325 + 1.326 +/* 1.327 + * The __sync_* family of intrinsics is documented here: 1.328 + * 1.329 + * http://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/Atomic-Builtins.html 1.330 + * 1.331 + * While these intrinsics are deprecated in favor of the newer __atomic_* 1.332 + * family of intrincs: 1.333 + * 1.334 + * http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/_005f_005fatomic-Builtins.html 1.335 + * 1.336 + * any GCC version that supports the __atomic_* intrinsics will also support 1.337 + * the <atomic> header and so will be handled above. We provide a version of 1.338 + * atomics using the __sync_* intrinsics to support older versions of GCC. 1.339 + * 1.340 + * All __sync_* intrinsics that we use below act as full memory barriers, for 1.341 + * both compiler and hardware reordering, except for __sync_lock_test_and_set, 1.342 + * which is a only an acquire barrier. When we call __sync_lock_test_and_set, 1.343 + * we add a barrier above it as appropriate. 1.344 + */ 1.345 + 1.346 +template<MemoryOrdering Order> struct Barrier; 1.347 + 1.348 +/* 1.349 + * Some processors (in particular, x86) don't require quite so many calls to 1.350 + * __sync_sychronize as our specializations of Barrier produce. If 1.351 + * performance turns out to be an issue, defining these specializations 1.352 + * on a per-processor basis would be a good first tuning step. 1.353 + */ 1.354 + 1.355 +template<> 1.356 +struct Barrier<Relaxed> 1.357 +{ 1.358 + static void beforeLoad() {} 1.359 + static void afterLoad() {} 1.360 + static void beforeStore() {} 1.361 + static void afterStore() {} 1.362 +}; 1.363 + 1.364 +template<> 1.365 +struct Barrier<ReleaseAcquire> 1.366 +{ 1.367 + static void beforeLoad() {} 1.368 + static void afterLoad() { __sync_synchronize(); } 1.369 + static void beforeStore() { __sync_synchronize(); } 1.370 + static void afterStore() {} 1.371 +}; 1.372 + 1.373 +template<> 1.374 +struct Barrier<SequentiallyConsistent> 1.375 +{ 1.376 + static void beforeLoad() { __sync_synchronize(); } 1.377 + static void afterLoad() { __sync_synchronize(); } 1.378 + static void beforeStore() { __sync_synchronize(); } 1.379 + static void afterStore() { __sync_synchronize(); } 1.380 +}; 1.381 + 1.382 +template<typename T, MemoryOrdering Order> 1.383 +struct IntrinsicMemoryOps 1.384 +{ 1.385 + static T load(const T& ptr) { 1.386 + Barrier<Order>::beforeLoad(); 1.387 + T val = ptr; 1.388 + Barrier<Order>::afterLoad(); 1.389 + return val; 1.390 + } 1.391 + static void store(T& ptr, T val) { 1.392 + Barrier<Order>::beforeStore(); 1.393 + ptr = val; 1.394 + Barrier<Order>::afterStore(); 1.395 + } 1.396 + static T exchange(T& ptr, T val) { 1.397 + // __sync_lock_test_and_set is only an acquire barrier; loads and stores 1.398 + // can't be moved up from after to before it, but they can be moved down 1.399 + // from before to after it. We may want a stricter ordering, so we need 1.400 + // an explicit barrier. 1.401 + 1.402 + Barrier<Order>::beforeStore(); 1.403 + return __sync_lock_test_and_set(&ptr, val); 1.404 + } 1.405 + static bool compareExchange(T& ptr, T oldVal, T newVal) { 1.406 + return __sync_bool_compare_and_swap(&ptr, oldVal, newVal); 1.407 + } 1.408 +}; 1.409 + 1.410 +template<typename T> 1.411 +struct IntrinsicAddSub 1.412 +{ 1.413 + typedef T ValueType; 1.414 + static T add(T& ptr, T val) { 1.415 + return __sync_fetch_and_add(&ptr, val); 1.416 + } 1.417 + static T sub(T& ptr, T val) { 1.418 + return __sync_fetch_and_sub(&ptr, val); 1.419 + } 1.420 +}; 1.421 + 1.422 +template<typename T> 1.423 +struct IntrinsicAddSub<T*> 1.424 +{ 1.425 + typedef T* ValueType; 1.426 + /* 1.427 + * The reinterpret_casts are needed so that 1.428 + * __sync_fetch_and_{add,sub} will properly type-check. 1.429 + * 1.430 + * Also, these functions do not provide standard semantics for 1.431 + * pointer types, so we need to adjust the addend. 1.432 + */ 1.433 + static ValueType add(ValueType& ptr, ptrdiff_t val) { 1.434 + ValueType amount = reinterpret_cast<ValueType>(val * sizeof(T)); 1.435 + return __sync_fetch_and_add(&ptr, amount); 1.436 + } 1.437 + static ValueType sub(ValueType& ptr, ptrdiff_t val) { 1.438 + ValueType amount = reinterpret_cast<ValueType>(val * sizeof(T)); 1.439 + return __sync_fetch_and_sub(&ptr, amount); 1.440 + } 1.441 +}; 1.442 + 1.443 +template<typename T> 1.444 +struct IntrinsicIncDec : public IntrinsicAddSub<T> 1.445 +{ 1.446 + static T inc(T& ptr) { return IntrinsicAddSub<T>::add(ptr, 1); } 1.447 + static T dec(T& ptr) { return IntrinsicAddSub<T>::sub(ptr, 1); } 1.448 +}; 1.449 + 1.450 +template<typename T, MemoryOrdering Order> 1.451 +struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>, 1.452 + public IntrinsicIncDec<T> 1.453 +{ 1.454 + static T or_(T& ptr, T val) { 1.455 + return __sync_fetch_and_or(&ptr, val); 1.456 + } 1.457 + static T xor_(T& ptr, T val) { 1.458 + return __sync_fetch_and_xor(&ptr, val); 1.459 + } 1.460 + static T and_(T& ptr, T val) { 1.461 + return __sync_fetch_and_and(&ptr, val); 1.462 + } 1.463 +}; 1.464 + 1.465 +template<typename T, MemoryOrdering Order> 1.466 +struct AtomicIntrinsics<T*, Order> : public IntrinsicMemoryOps<T*, Order>, 1.467 + public IntrinsicIncDec<T*> 1.468 +{ 1.469 +}; 1.470 + 1.471 +} // namespace detail 1.472 +} // namespace mozilla 1.473 + 1.474 +#elif defined(_MSC_VER) 1.475 + 1.476 +/* 1.477 + * Windows comes with a full complement of atomic operations. 1.478 + * Unfortunately, most of those aren't available for Windows XP (even if 1.479 + * the compiler supports intrinsics for them), which is the oldest 1.480 + * version of Windows we support. Therefore, we only provide operations 1.481 + * on 32-bit datatypes for 32-bit Windows versions; for 64-bit Windows 1.482 + * versions, we support 64-bit datatypes as well. 1.483 + * 1.484 + * To avoid namespace pollution issues, we declare whatever functions we 1.485 + * need ourselves. 1.486 + */ 1.487 + 1.488 +extern "C" { 1.489 +long __cdecl _InterlockedExchangeAdd(long volatile* dst, long value); 1.490 +long __cdecl _InterlockedOr(long volatile* dst, long value); 1.491 +long __cdecl _InterlockedXor(long volatile* dst, long value); 1.492 +long __cdecl _InterlockedAnd(long volatile* dst, long value); 1.493 +long __cdecl _InterlockedExchange(long volatile *dst, long value); 1.494 +long __cdecl _InterlockedCompareExchange(long volatile *dst, long newVal, long oldVal); 1.495 +} 1.496 + 1.497 +# pragma intrinsic(_InterlockedExchangeAdd) 1.498 +# pragma intrinsic(_InterlockedOr) 1.499 +# pragma intrinsic(_InterlockedXor) 1.500 +# pragma intrinsic(_InterlockedAnd) 1.501 +# pragma intrinsic(_InterlockedExchange) 1.502 +# pragma intrinsic(_InterlockedCompareExchange) 1.503 + 1.504 +namespace mozilla { 1.505 +namespace detail { 1.506 + 1.507 +# if !defined(_M_IX86) && !defined(_M_X64) 1.508 + /* 1.509 + * The implementations below are optimized for x86ish systems. You 1.510 + * will have to modify them if you are porting to Windows on a 1.511 + * different architecture. 1.512 + */ 1.513 +# error "Unknown CPU type" 1.514 +# endif 1.515 + 1.516 +/* 1.517 + * The PrimitiveIntrinsics template should define |Type|, the datatype of size 1.518 + * DataSize upon which we operate, and the following eight functions. 1.519 + * 1.520 + * static Type add(Type* ptr, Type val); 1.521 + * static Type sub(Type* ptr, Type val); 1.522 + * static Type or_(Type* ptr, Type val); 1.523 + * static Type xor_(Type* ptr, Type val); 1.524 + * static Type and_(Type* ptr, Type val); 1.525 + * 1.526 + * These functions perform the obvious operation on the value contained in 1.527 + * |*ptr| combined with |val| and return the value previously stored in 1.528 + * |*ptr|. 1.529 + * 1.530 + * static void store(Type* ptr, Type val); 1.531 + * 1.532 + * This function atomically stores |val| into |*ptr| and must provide a full 1.533 + * memory fence after the store to prevent compiler and hardware instruction 1.534 + * reordering. It should also act as a compiler barrier to prevent reads and 1.535 + * writes from moving to after the store. 1.536 + * 1.537 + * static Type exchange(Type* ptr, Type val); 1.538 + * 1.539 + * This function atomically stores |val| into |*ptr| and returns the previous 1.540 + * contents of *ptr; 1.541 + * 1.542 + * static bool compareExchange(Type* ptr, Type oldVal, Type newVal); 1.543 + * 1.544 + * This function atomically performs the following operation: 1.545 + * 1.546 + * if (*ptr == oldVal) { 1.547 + * *ptr = newVal; 1.548 + * return true; 1.549 + * } else { 1.550 + * return false; 1.551 + * } 1.552 + * 1.553 + */ 1.554 +template<size_t DataSize> struct PrimitiveIntrinsics; 1.555 + 1.556 +template<> 1.557 +struct PrimitiveIntrinsics<4> 1.558 +{ 1.559 + typedef long Type; 1.560 + 1.561 + static Type add(Type* ptr, Type val) { 1.562 + return _InterlockedExchangeAdd(ptr, val); 1.563 + } 1.564 + static Type sub(Type* ptr, Type val) { 1.565 + /* 1.566 + * _InterlockedExchangeSubtract isn't available before Windows 7, 1.567 + * and we must support Windows XP. 1.568 + */ 1.569 + return _InterlockedExchangeAdd(ptr, -val); 1.570 + } 1.571 + static Type or_(Type* ptr, Type val) { 1.572 + return _InterlockedOr(ptr, val); 1.573 + } 1.574 + static Type xor_(Type* ptr, Type val) { 1.575 + return _InterlockedXor(ptr, val); 1.576 + } 1.577 + static Type and_(Type* ptr, Type val) { 1.578 + return _InterlockedAnd(ptr, val); 1.579 + } 1.580 + static void store(Type* ptr, Type val) { 1.581 + _InterlockedExchange(ptr, val); 1.582 + } 1.583 + static Type exchange(Type* ptr, Type val) { 1.584 + return _InterlockedExchange(ptr, val); 1.585 + } 1.586 + static bool compareExchange(Type* ptr, Type oldVal, Type newVal) { 1.587 + return _InterlockedCompareExchange(ptr, newVal, oldVal) == oldVal; 1.588 + } 1.589 +}; 1.590 + 1.591 +# if defined(_M_X64) 1.592 + 1.593 +extern "C" { 1.594 +long long __cdecl _InterlockedExchangeAdd64(long long volatile* dst, 1.595 + long long value); 1.596 +long long __cdecl _InterlockedOr64(long long volatile* dst, 1.597 + long long value); 1.598 +long long __cdecl _InterlockedXor64(long long volatile* dst, 1.599 + long long value); 1.600 +long long __cdecl _InterlockedAnd64(long long volatile* dst, 1.601 + long long value); 1.602 +long long __cdecl _InterlockedExchange64(long long volatile* dst, 1.603 + long long value); 1.604 +long long __cdecl _InterlockedCompareExchange64(long long volatile* dst, 1.605 + long long newVal, 1.606 + long long oldVal); 1.607 +} 1.608 + 1.609 +# pragma intrinsic(_InterlockedExchangeAdd64) 1.610 +# pragma intrinsic(_InterlockedOr64) 1.611 +# pragma intrinsic(_InterlockedXor64) 1.612 +# pragma intrinsic(_InterlockedAnd64) 1.613 +# pragma intrinsic(_InterlockedExchange64) 1.614 +# pragma intrinsic(_InterlockedCompareExchange64) 1.615 + 1.616 +template <> 1.617 +struct PrimitiveIntrinsics<8> 1.618 +{ 1.619 + typedef __int64 Type; 1.620 + 1.621 + static Type add(Type* ptr, Type val) { 1.622 + return _InterlockedExchangeAdd64(ptr, val); 1.623 + } 1.624 + static Type sub(Type* ptr, Type val) { 1.625 + /* 1.626 + * There is no _InterlockedExchangeSubtract64. 1.627 + */ 1.628 + return _InterlockedExchangeAdd64(ptr, -val); 1.629 + } 1.630 + static Type or_(Type* ptr, Type val) { 1.631 + return _InterlockedOr64(ptr, val); 1.632 + } 1.633 + static Type xor_(Type* ptr, Type val) { 1.634 + return _InterlockedXor64(ptr, val); 1.635 + } 1.636 + static Type and_(Type* ptr, Type val) { 1.637 + return _InterlockedAnd64(ptr, val); 1.638 + } 1.639 + static void store(Type* ptr, Type val) { 1.640 + _InterlockedExchange64(ptr, val); 1.641 + } 1.642 + static Type exchange(Type* ptr, Type val) { 1.643 + return _InterlockedExchange64(ptr, val); 1.644 + } 1.645 + static bool compareExchange(Type* ptr, Type oldVal, Type newVal) { 1.646 + return _InterlockedCompareExchange64(ptr, newVal, oldVal) == oldVal; 1.647 + } 1.648 +}; 1.649 + 1.650 +# endif 1.651 + 1.652 +extern "C" { void _ReadWriteBarrier(); } 1.653 + 1.654 +# pragma intrinsic(_ReadWriteBarrier) 1.655 + 1.656 +template<MemoryOrdering Order> struct Barrier; 1.657 + 1.658 +/* 1.659 + * We do not provide an afterStore method in Barrier, as Relaxed and 1.660 + * ReleaseAcquire orderings do not require one, and the required barrier 1.661 + * for SequentiallyConsistent is handled by PrimitiveIntrinsics. 1.662 + */ 1.663 + 1.664 +template<> 1.665 +struct Barrier<Relaxed> 1.666 +{ 1.667 + static void beforeLoad() {} 1.668 + static void afterLoad() {} 1.669 + static void beforeStore() {} 1.670 +}; 1.671 + 1.672 +template<> 1.673 +struct Barrier<ReleaseAcquire> 1.674 +{ 1.675 + static void beforeLoad() {} 1.676 + static void afterLoad() { _ReadWriteBarrier(); } 1.677 + static void beforeStore() { _ReadWriteBarrier(); } 1.678 +}; 1.679 + 1.680 +template<> 1.681 +struct Barrier<SequentiallyConsistent> 1.682 +{ 1.683 + static void beforeLoad() { _ReadWriteBarrier(); } 1.684 + static void afterLoad() { _ReadWriteBarrier(); } 1.685 + static void beforeStore() { _ReadWriteBarrier(); } 1.686 +}; 1.687 + 1.688 +template<typename PrimType, typename T> 1.689 +struct CastHelper 1.690 +{ 1.691 + static PrimType toPrimType(T val) { return static_cast<PrimType>(val); } 1.692 + static T fromPrimType(PrimType val) { return static_cast<T>(val); } 1.693 +}; 1.694 + 1.695 +template<typename PrimType, typename T> 1.696 +struct CastHelper<PrimType, T*> 1.697 +{ 1.698 + static PrimType toPrimType(T* val) { return reinterpret_cast<PrimType>(val); } 1.699 + static T* fromPrimType(PrimType val) { return reinterpret_cast<T*>(val); } 1.700 +}; 1.701 + 1.702 +template<typename T> 1.703 +struct IntrinsicBase 1.704 +{ 1.705 + typedef T ValueType; 1.706 + typedef PrimitiveIntrinsics<sizeof(T)> Primitives; 1.707 + typedef typename Primitives::Type PrimType; 1.708 + static_assert(sizeof(PrimType) == sizeof(T), 1.709 + "Selection of PrimitiveIntrinsics was wrong"); 1.710 + typedef CastHelper<PrimType, T> Cast; 1.711 +}; 1.712 + 1.713 +template<typename T, MemoryOrdering Order> 1.714 +struct IntrinsicMemoryOps : public IntrinsicBase<T> 1.715 +{ 1.716 + typedef typename IntrinsicBase<T>::ValueType ValueType; 1.717 + typedef typename IntrinsicBase<T>::Primitives Primitives; 1.718 + typedef typename IntrinsicBase<T>::PrimType PrimType; 1.719 + typedef typename IntrinsicBase<T>::Cast Cast; 1.720 + static ValueType load(const ValueType& ptr) { 1.721 + Barrier<Order>::beforeLoad(); 1.722 + ValueType val = ptr; 1.723 + Barrier<Order>::afterLoad(); 1.724 + return val; 1.725 + } 1.726 + static void store(ValueType& ptr, ValueType val) { 1.727 + // For SequentiallyConsistent, Primitives::store() will generate the 1.728 + // proper memory fence. Everything else just needs a barrier before 1.729 + // the store. 1.730 + if (Order == SequentiallyConsistent) { 1.731 + Primitives::store(reinterpret_cast<PrimType*>(&ptr), 1.732 + Cast::toPrimType(val)); 1.733 + } else { 1.734 + Barrier<Order>::beforeStore(); 1.735 + ptr = val; 1.736 + } 1.737 + } 1.738 + static ValueType exchange(ValueType& ptr, ValueType val) { 1.739 + PrimType oldval = 1.740 + Primitives::exchange(reinterpret_cast<PrimType*>(&ptr), 1.741 + Cast::toPrimType(val)); 1.742 + return Cast::fromPrimType(oldval); 1.743 + } 1.744 + static bool compareExchange(ValueType& ptr, ValueType oldVal, ValueType newVal) { 1.745 + return Primitives::compareExchange(reinterpret_cast<PrimType*>(&ptr), 1.746 + Cast::toPrimType(oldVal), 1.747 + Cast::toPrimType(newVal)); 1.748 + } 1.749 +}; 1.750 + 1.751 +template<typename T> 1.752 +struct IntrinsicApplyHelper : public IntrinsicBase<T> 1.753 +{ 1.754 + typedef typename IntrinsicBase<T>::ValueType ValueType; 1.755 + typedef typename IntrinsicBase<T>::PrimType PrimType; 1.756 + typedef typename IntrinsicBase<T>::Cast Cast; 1.757 + typedef PrimType (*BinaryOp)(PrimType*, PrimType); 1.758 + typedef PrimType (*UnaryOp)(PrimType*); 1.759 + 1.760 + static ValueType applyBinaryFunction(BinaryOp op, ValueType& ptr, 1.761 + ValueType val) { 1.762 + PrimType* primTypePtr = reinterpret_cast<PrimType*>(&ptr); 1.763 + PrimType primTypeVal = Cast::toPrimType(val); 1.764 + return Cast::fromPrimType(op(primTypePtr, primTypeVal)); 1.765 + } 1.766 + 1.767 + static ValueType applyUnaryFunction(UnaryOp op, ValueType& ptr) { 1.768 + PrimType* primTypePtr = reinterpret_cast<PrimType*>(&ptr); 1.769 + return Cast::fromPrimType(op(primTypePtr)); 1.770 + } 1.771 +}; 1.772 + 1.773 +template<typename T> 1.774 +struct IntrinsicAddSub : public IntrinsicApplyHelper<T> 1.775 +{ 1.776 + typedef typename IntrinsicApplyHelper<T>::ValueType ValueType; 1.777 + typedef typename IntrinsicBase<T>::Primitives Primitives; 1.778 + static ValueType add(ValueType& ptr, ValueType val) { 1.779 + return applyBinaryFunction(&Primitives::add, ptr, val); 1.780 + } 1.781 + static ValueType sub(ValueType& ptr, ValueType val) { 1.782 + return applyBinaryFunction(&Primitives::sub, ptr, val); 1.783 + } 1.784 +}; 1.785 + 1.786 +template<typename T> 1.787 +struct IntrinsicAddSub<T*> : public IntrinsicApplyHelper<T*> 1.788 +{ 1.789 + typedef typename IntrinsicApplyHelper<T*>::ValueType ValueType; 1.790 + static ValueType add(ValueType& ptr, ptrdiff_t amount) { 1.791 + return applyBinaryFunction(&Primitives::add, ptr, 1.792 + (ValueType)(amount * sizeof(ValueType))); 1.793 + } 1.794 + static ValueType sub(ValueType& ptr, ptrdiff_t amount) { 1.795 + return applyBinaryFunction(&Primitives::sub, ptr, 1.796 + (ValueType)(amount * sizeof(ValueType))); 1.797 + } 1.798 +}; 1.799 + 1.800 +template<typename T> 1.801 +struct IntrinsicIncDec : public IntrinsicAddSub<T> 1.802 +{ 1.803 + typedef typename IntrinsicAddSub<T>::ValueType ValueType; 1.804 + static ValueType inc(ValueType& ptr) { return add(ptr, 1); } 1.805 + static ValueType dec(ValueType& ptr) { return sub(ptr, 1); } 1.806 +}; 1.807 + 1.808 +template<typename T, MemoryOrdering Order> 1.809 +struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>, 1.810 + public IntrinsicIncDec<T> 1.811 +{ 1.812 + typedef typename IntrinsicIncDec<T>::ValueType ValueType; 1.813 + static ValueType or_(ValueType& ptr, T val) { 1.814 + return applyBinaryFunction(&Primitives::or_, ptr, val); 1.815 + } 1.816 + static ValueType xor_(ValueType& ptr, T val) { 1.817 + return applyBinaryFunction(&Primitives::xor_, ptr, val); 1.818 + } 1.819 + static ValueType and_(ValueType& ptr, T val) { 1.820 + return applyBinaryFunction(&Primitives::and_, ptr, val); 1.821 + } 1.822 +}; 1.823 + 1.824 +template<typename T, MemoryOrdering Order> 1.825 +struct AtomicIntrinsics<T*, Order> : public IntrinsicMemoryOps<T*, Order>, 1.826 + public IntrinsicIncDec<T*> 1.827 +{ 1.828 + typedef typename IntrinsicMemoryOps<T*, Order>::ValueType ValueType; 1.829 +}; 1.830 + 1.831 +} // namespace detail 1.832 +} // namespace mozilla 1.833 + 1.834 +#else 1.835 +# error "Atomic compiler intrinsics are not supported on your platform" 1.836 +#endif 1.837 + 1.838 +namespace mozilla { 1.839 + 1.840 +namespace detail { 1.841 + 1.842 +template<typename T, MemoryOrdering Order> 1.843 +class AtomicBase 1.844 +{ 1.845 + // We only support 32-bit types on 32-bit Windows, which constrains our 1.846 + // implementation elsewhere. But we support pointer-sized types everywhere. 1.847 + static_assert(sizeof(T) == 4 || (sizeof(uintptr_t) == 8 && sizeof(T) == 8), 1.848 + "mozilla/Atomics.h only supports 32-bit and pointer-sized types"); 1.849 + 1.850 + protected: 1.851 + typedef typename detail::AtomicIntrinsics<T, Order> Intrinsics; 1.852 + typename Intrinsics::ValueType mValue; 1.853 + 1.854 + public: 1.855 + MOZ_CONSTEXPR AtomicBase() : mValue() {} 1.856 + MOZ_CONSTEXPR AtomicBase(T aInit) : mValue(aInit) {} 1.857 + 1.858 + // Note: we can't provide operator T() here because Atomic<bool> inherits 1.859 + // from AtomcBase with T=uint32_t and not T=bool. If we implemented 1.860 + // operator T() here, it would cause errors when comparing Atomic<bool> with 1.861 + // a regular bool. 1.862 + 1.863 + T operator=(T aValue) { 1.864 + Intrinsics::store(mValue, aValue); 1.865 + return aValue; 1.866 + } 1.867 + 1.868 + /** 1.869 + * Performs an atomic swap operation. aValue is stored and the previous 1.870 + * value of this variable is returned. 1.871 + */ 1.872 + T exchange(T aValue) { 1.873 + return Intrinsics::exchange(mValue, aValue); 1.874 + } 1.875 + 1.876 + /** 1.877 + * Performs an atomic compare-and-swap operation and returns true if it 1.878 + * succeeded. This is equivalent to atomically doing 1.879 + * 1.880 + * if (mValue == aOldValue) { 1.881 + * mValue = aNewValue; 1.882 + * return true; 1.883 + * } else { 1.884 + * return false; 1.885 + * } 1.886 + */ 1.887 + bool compareExchange(T aOldValue, T aNewValue) { 1.888 + return Intrinsics::compareExchange(mValue, aOldValue, aNewValue); 1.889 + } 1.890 + 1.891 + private: 1.892 + template<MemoryOrdering AnyOrder> 1.893 + AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) MOZ_DELETE; 1.894 +}; 1.895 + 1.896 +template<typename T, MemoryOrdering Order> 1.897 +class AtomicBaseIncDec : public AtomicBase<T, Order> 1.898 +{ 1.899 + typedef typename detail::AtomicBase<T, Order> Base; 1.900 + 1.901 + public: 1.902 + MOZ_CONSTEXPR AtomicBaseIncDec() : Base() {} 1.903 + MOZ_CONSTEXPR AtomicBaseIncDec(T aInit) : Base(aInit) {} 1.904 + 1.905 + using Base::operator=; 1.906 + 1.907 + operator T() const { return Base::Intrinsics::load(Base::mValue); } 1.908 + T operator++(int) { return Base::Intrinsics::inc(Base::mValue); } 1.909 + T operator--(int) { return Base::Intrinsics::dec(Base::mValue); } 1.910 + T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; } 1.911 + T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; } 1.912 + 1.913 + private: 1.914 + template<MemoryOrdering AnyOrder> 1.915 + AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) MOZ_DELETE; 1.916 +}; 1.917 + 1.918 +} // namespace detail 1.919 + 1.920 +/** 1.921 + * A wrapper for a type that enforces that all memory accesses are atomic. 1.922 + * 1.923 + * In general, where a variable |T foo| exists, |Atomic<T> foo| can be used in 1.924 + * its place. Implementations for integral and pointer types are provided 1.925 + * below. 1.926 + * 1.927 + * Atomic accesses are sequentially consistent by default. You should 1.928 + * use the default unless you are tall enough to ride the 1.929 + * memory-ordering roller coaster (if you're not sure, you aren't) and 1.930 + * you have a compelling reason to do otherwise. 1.931 + * 1.932 + * There is one exception to the case of atomic memory accesses: providing an 1.933 + * initial value of the atomic value is not guaranteed to be atomic. This is a 1.934 + * deliberate design choice that enables static atomic variables to be declared 1.935 + * without introducing extra static constructors. 1.936 + */ 1.937 +template<typename T, 1.938 + MemoryOrdering Order = SequentiallyConsistent, 1.939 + typename Enable = void> 1.940 +class Atomic; 1.941 + 1.942 +/** 1.943 + * Atomic<T> implementation for integral types. 1.944 + * 1.945 + * In addition to atomic store and load operations, compound assignment and 1.946 + * increment/decrement operators are implemented which perform the 1.947 + * corresponding read-modify-write operation atomically. Finally, an atomic 1.948 + * swap method is provided. 1.949 + */ 1.950 +template<typename T, MemoryOrdering Order> 1.951 +class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value && !IsSame<T, bool>::value>::Type> 1.952 + : public detail::AtomicBaseIncDec<T, Order> 1.953 +{ 1.954 + typedef typename detail::AtomicBaseIncDec<T, Order> Base; 1.955 + 1.956 + public: 1.957 + MOZ_CONSTEXPR Atomic() : Base() {} 1.958 + MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} 1.959 + 1.960 + using Base::operator=; 1.961 + 1.962 + T operator+=(T delta) { return Base::Intrinsics::add(Base::mValue, delta) + delta; } 1.963 + T operator-=(T delta) { return Base::Intrinsics::sub(Base::mValue, delta) - delta; } 1.964 + T operator|=(T val) { return Base::Intrinsics::or_(Base::mValue, val) | val; } 1.965 + T operator^=(T val) { return Base::Intrinsics::xor_(Base::mValue, val) ^ val; } 1.966 + T operator&=(T val) { return Base::Intrinsics::and_(Base::mValue, val) & val; } 1.967 + 1.968 + private: 1.969 + Atomic(Atomic<T, Order>& aOther) MOZ_DELETE; 1.970 +}; 1.971 + 1.972 +/** 1.973 + * Atomic<T> implementation for pointer types. 1.974 + * 1.975 + * An atomic compare-and-swap primitive for pointer variables is provided, as 1.976 + * are atomic increment and decement operators. Also provided are the compound 1.977 + * assignment operators for addition and subtraction. Atomic swap (via 1.978 + * exchange()) is included as well. 1.979 + */ 1.980 +template<typename T, MemoryOrdering Order> 1.981 +class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order> 1.982 +{ 1.983 + typedef typename detail::AtomicBaseIncDec<T*, Order> Base; 1.984 + 1.985 + public: 1.986 + MOZ_CONSTEXPR Atomic() : Base() {} 1.987 + MOZ_CONSTEXPR Atomic(T* aInit) : Base(aInit) {} 1.988 + 1.989 + using Base::operator=; 1.990 + 1.991 + T* operator+=(ptrdiff_t delta) { 1.992 + return Base::Intrinsics::add(Base::mValue, delta) + delta; 1.993 + } 1.994 + T* operator-=(ptrdiff_t delta) { 1.995 + return Base::Intrinsics::sub(Base::mValue, delta) - delta; 1.996 + } 1.997 + 1.998 + private: 1.999 + Atomic(Atomic<T*, Order>& aOther) MOZ_DELETE; 1.1000 +}; 1.1001 + 1.1002 +/** 1.1003 + * Atomic<T> implementation for enum types. 1.1004 + * 1.1005 + * The atomic store and load operations and the atomic swap method is provided. 1.1006 + */ 1.1007 +template<typename T, MemoryOrdering Order> 1.1008 +class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type> 1.1009 + : public detail::AtomicBase<T, Order> 1.1010 +{ 1.1011 + typedef typename detail::AtomicBase<T, Order> Base; 1.1012 + 1.1013 + public: 1.1014 + MOZ_CONSTEXPR Atomic() : Base() {} 1.1015 + MOZ_CONSTEXPR Atomic(T aInit) : Base(aInit) {} 1.1016 + 1.1017 + operator T() const { return Base::Intrinsics::load(Base::mValue); } 1.1018 + 1.1019 + using Base::operator=; 1.1020 + 1.1021 + private: 1.1022 + Atomic(Atomic<T, Order>& aOther) MOZ_DELETE; 1.1023 +}; 1.1024 + 1.1025 +/** 1.1026 + * Atomic<T> implementation for boolean types. 1.1027 + * 1.1028 + * The atomic store and load operations and the atomic swap method is provided. 1.1029 + * 1.1030 + * Note: 1.1031 + * 1.1032 + * - sizeof(Atomic<bool>) != sizeof(bool) for some implementations of 1.1033 + * bool and/or some implementations of std::atomic. This is allowed in 1.1034 + * [atomic.types.generic]p9. 1.1035 + * 1.1036 + * - It's not obvious whether the 8-bit atomic functions on Windows are always 1.1037 + * inlined or not. If they are not inlined, the corresponding functions in the 1.1038 + * runtime library are not available on Windows XP. This is why we implement 1.1039 + * Atomic<bool> with an underlying type of uint32_t. 1.1040 + */ 1.1041 +template<MemoryOrdering Order> 1.1042 +class Atomic<bool, Order> 1.1043 + : protected detail::AtomicBase<uint32_t, Order> 1.1044 +{ 1.1045 + typedef typename detail::AtomicBase<uint32_t, Order> Base; 1.1046 + 1.1047 + public: 1.1048 + MOZ_CONSTEXPR Atomic() : Base() {} 1.1049 + MOZ_CONSTEXPR Atomic(bool aInit) : Base(aInit) {} 1.1050 + 1.1051 + // We provide boolean wrappers for the underlying AtomicBase methods. 1.1052 + operator bool() const { return Base::Intrinsics::load(Base::mValue); } 1.1053 + bool operator=(bool aValue) { return Base::operator=(aValue); } 1.1054 + bool exchange(bool aValue) { return Base::exchange(aValue); } 1.1055 + bool compareExchange(bool aOldValue, bool aNewValue) { 1.1056 + return Base::compareExchange(aOldValue, aNewValue); 1.1057 + } 1.1058 + 1.1059 + private: 1.1060 + Atomic(Atomic<bool, Order>& aOther) MOZ_DELETE; 1.1061 +}; 1.1062 + 1.1063 +} // namespace mozilla 1.1064 + 1.1065 +#endif /* mozilla_Atomics_h */