Bug 1499346 [wpt PR 13540] - Use a common blank reference for wpt/css., a=testonly
[gecko.git] / mfbt / Atomics.h
blob6528a5763314e285e133545cc7b2b00b688010f4
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Implements (almost always) lock-free atomic operations. The operations here
9 * are a subset of that which can be found in C++11's <atomic> header, with a
10 * different API to enforce consistent memory ordering constraints.
12 * Anyone caught using |volatile| for inter-thread memory safety needs to be
13 * sent a copy of this header and the C++11 standard.
16 #ifndef mozilla_Atomics_h
17 #define mozilla_Atomics_h
19 #include "mozilla/Assertions.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/Compiler.h"
22 #include "mozilla/RecordReplay.h"
23 #include "mozilla/TypeTraits.h"
25 #include <atomic>
27 #include <stdint.h>
29 namespace mozilla {
31 /**
32 * An enum of memory ordering possibilities for atomics.
34 * Memory ordering is the observable state of distinct values in memory.
35 * (It's a separate concept from atomicity, which concerns whether an
36 * operation can ever be observed in an intermediate state. Don't
37 * conflate the two!) Given a sequence of operations in source code on
38 * memory, it is *not* always the case that, at all times and on all
39 * cores, those operations will appear to have occurred in that exact
40 * sequence. First, the compiler might reorder that sequence, if it
41 * thinks another ordering will be more efficient. Second, the CPU may
42 * not expose so consistent a view of memory. CPUs will often perform
43 * their own instruction reordering, above and beyond that performed by
44 * the compiler. And each core has its own memory caches, and accesses
45 * (reads and writes both) to "memory" may only resolve to out-of-date
46 * cache entries -- not to the "most recently" performed operation in
47 * some global sense. Any access to a value that may be used by
48 * multiple threads, potentially across multiple cores, must therefore
49 * have a memory ordering imposed on it, for all code on all
50 * threads/cores to have a sufficiently coherent worldview.
52 * http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and
53 * http://en.cppreference.com/w/cpp/atomic/memory_order go into more
54 * detail on all this, including examples of how each mode works.
56 * Note that for simplicity and practicality, not all of the modes in
57 * C++11 are supported. The missing C++11 modes are either subsumed by
58 * the modes we provide below, or not relevant for the CPUs we support
59 * in Gecko. These three modes are confusing enough as it is!
61 enum MemoryOrdering {
63 * Relaxed ordering is the simplest memory ordering: none at all.
64 * When the result of a write is observed, nothing may be inferred
65 * about other memory. Writes ostensibly performed "before" on the
66 * writing thread may not yet be visible. Writes performed "after" on
67 * the writing thread may already be visible, if the compiler or CPU
68 * reordered them. (The latter can happen if reads and/or writes get
69 * held up in per-processor caches.) Relaxed ordering means
70 * operations can always use cached values (as long as the actual
71 * updates to atomic values actually occur, correctly, eventually), so
72 * it's usually the fastest sort of atomic access. For this reason,
73 * *it's also the most dangerous kind of access*.
75 * Relaxed ordering is good for things like process-wide statistics
76 * counters that don't need to be consistent with anything else, so
77 * long as updates themselves are atomic. (And so long as any
78 * observations of that value can tolerate being out-of-date -- if you
79 * need some sort of up-to-date value, you need some sort of other
80 * synchronizing operation.) It's *not* good for locks, mutexes,
81 * reference counts, etc. that mediate access to other memory, or must
82 * be observably consistent with other memory.
84 * x86 architectures don't take advantage of the optimization
85 * opportunities that relaxed ordering permits. Thus it's possible
86 * that using relaxed ordering will "work" on x86 but fail elsewhere
87 * (ARM, say, which *does* implement non-sequentially-consistent
88 * relaxed ordering semantics). Be extra-careful using relaxed
89 * ordering if you can't easily test non-x86 architectures!
91 Relaxed,
94 * When an atomic value is updated with ReleaseAcquire ordering, and
95 * that new value is observed with ReleaseAcquire ordering, prior
96 * writes (atomic or not) are also observable. What ReleaseAcquire
97 * *doesn't* give you is any observable ordering guarantees for
98 * ReleaseAcquire-ordered operations on different objects. For
99 * example, if there are two cores that each perform ReleaseAcquire
100 * operations on separate objects, each core may or may not observe
101 * the operations made by the other core. The only way the cores can
102 * be synchronized with ReleaseAcquire is if they both
103 * ReleaseAcquire-access the same object. This implies that you can't
104 * necessarily describe some global total ordering of ReleaseAcquire
105 * operations.
107 * ReleaseAcquire ordering is good for (as the name implies) atomic
108 * operations on values controlling ownership of things: reference
109 * counts, mutexes, and the like. However, if you are thinking about
110 * using these to implement your own locks or mutexes, you should take
111 * a good, hard look at actual lock or mutex primitives first.
113 ReleaseAcquire,
116 * When an atomic value is updated with SequentiallyConsistent
117 * ordering, all writes observable when the update is observed, just
118 * as with ReleaseAcquire ordering. But, furthermore, a global total
119 * ordering of SequentiallyConsistent operations *can* be described.
120 * For example, if two cores perform SequentiallyConsistent operations
121 * on separate objects, one core will observably perform its update
122 * (and all previous operations will have completed), then the other
123 * core will observably perform its update (and all previous
124 * operations will have completed). (Although those previous
125 * operations aren't themselves ordered -- they could be intermixed,
126 * or ordered if they occur on atomic values with ordering
127 * requirements.) SequentiallyConsistent is the *simplest and safest*
128 * ordering of atomic operations -- it's always as if one operation
129 * happens, then another, then another, in some order -- and every
130 * core observes updates to happen in that single order. Because it
131 * has the most synchronization requirements, operations ordered this
132 * way also tend to be slowest.
134 * SequentiallyConsistent ordering can be desirable when multiple
135 * threads observe objects, and they all have to agree on the
136 * observable order of changes to them. People expect
137 * SequentiallyConsistent ordering, even if they shouldn't, when
138 * writing code, atomic or otherwise. SequentiallyConsistent is also
139 * the ordering of choice when designing lockless data structures. If
140 * you don't know what order to use, use this one.
142 SequentiallyConsistent,
145 namespace detail {
148 * Structure which can be used to preserve the ordering of atomic accesses
149 * when recording or replaying an execution, depending on the Recording enum.
151 * Atomic access ordering is preserved by default when recording/replaying.
152 * This should be overridden for atomics that can be accessed in code that
153 * runs non-deterministically when recording/replaying, such as during GC, the
154 * JS interrupt callback, or code that is affected by JIT compilation or
155 * debugger activity.
157 template<recordreplay::Behavior Recording> struct AutoRecordAtomicAccess;
159 template<>
160 struct AutoRecordAtomicAccess<recordreplay::Behavior::DontPreserve> {
161 explicit AutoRecordAtomicAccess(const void* aValue) {}
162 ~AutoRecordAtomicAccess() {}
165 template<>
166 struct AutoRecordAtomicAccess<recordreplay::Behavior::Preserve> {
167 explicit AutoRecordAtomicAccess(const void* aValue) { recordreplay::BeginOrderedAtomicAccess(aValue); }
168 ~AutoRecordAtomicAccess() { recordreplay::EndOrderedAtomicAccess(); }
172 * We provide CompareExchangeFailureOrder to work around a bug in some
173 * versions of GCC's <atomic> header. See bug 898491.
175 template<MemoryOrdering Order> struct AtomicOrderConstraints;
177 template<>
178 struct AtomicOrderConstraints<Relaxed>
180 static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed;
181 static const std::memory_order LoadOrder = std::memory_order_relaxed;
182 static const std::memory_order StoreOrder = std::memory_order_relaxed;
183 static const std::memory_order CompareExchangeFailureOrder =
184 std::memory_order_relaxed;
187 template<>
188 struct AtomicOrderConstraints<ReleaseAcquire>
190 static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel;
191 static const std::memory_order LoadOrder = std::memory_order_acquire;
192 static const std::memory_order StoreOrder = std::memory_order_release;
193 static const std::memory_order CompareExchangeFailureOrder =
194 std::memory_order_acquire;
197 template<>
198 struct AtomicOrderConstraints<SequentiallyConsistent>
200 static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst;
201 static const std::memory_order LoadOrder = std::memory_order_seq_cst;
202 static const std::memory_order StoreOrder = std::memory_order_seq_cst;
203 static const std::memory_order CompareExchangeFailureOrder =
204 std::memory_order_seq_cst;
207 template<typename T, MemoryOrdering Order>
208 struct IntrinsicBase
210 typedef std::atomic<T> ValueType;
211 typedef AtomicOrderConstraints<Order> OrderedOp;
214 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
215 struct IntrinsicMemoryOps : public IntrinsicBase<T, Order>
217 typedef IntrinsicBase<T, Order> Base;
219 static T load(const typename Base::ValueType& aPtr)
221 AutoRecordAtomicAccess<Recording> record(&aPtr);
222 return aPtr.load(Base::OrderedOp::LoadOrder);
225 static void store(typename Base::ValueType& aPtr, T aVal)
227 AutoRecordAtomicAccess<Recording> record(&aPtr);
228 aPtr.store(aVal, Base::OrderedOp::StoreOrder);
231 static T exchange(typename Base::ValueType& aPtr, T aVal)
233 AutoRecordAtomicAccess<Recording> record(&aPtr);
234 return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder);
237 static bool compareExchange(typename Base::ValueType& aPtr,
238 T aOldVal, T aNewVal)
240 AutoRecordAtomicAccess<Recording> record(&aPtr);
241 return aPtr.compare_exchange_strong(aOldVal, aNewVal,
242 Base::OrderedOp::AtomicRMWOrder,
243 Base::OrderedOp::CompareExchangeFailureOrder);
247 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
248 struct IntrinsicAddSub : public IntrinsicBase<T, Order>
250 typedef IntrinsicBase<T, Order> Base;
252 static T add(typename Base::ValueType& aPtr, T aVal)
254 AutoRecordAtomicAccess<Recording> record(&aPtr);
255 return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
258 static T sub(typename Base::ValueType& aPtr, T aVal)
260 AutoRecordAtomicAccess<Recording> record(&aPtr);
261 return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
265 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
266 struct IntrinsicAddSub<T*, Order, Recording> : public IntrinsicBase<T*, Order>
268 typedef IntrinsicBase<T*, Order> Base;
270 static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
272 AutoRecordAtomicAccess<Recording> record(&aPtr);
273 return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
276 static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
278 AutoRecordAtomicAccess<Recording> record(&aPtr);
279 return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
283 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
284 struct IntrinsicIncDec : public IntrinsicAddSub<T, Order, Recording>
286 typedef IntrinsicBase<T, Order> Base;
288 static T inc(typename Base::ValueType& aPtr)
290 return IntrinsicAddSub<T, Order, Recording>::add(aPtr, 1);
293 static T dec(typename Base::ValueType& aPtr)
295 return IntrinsicAddSub<T, Order, Recording>::sub(aPtr, 1);
299 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
300 struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order, Recording>,
301 public IntrinsicIncDec<T, Order, Recording>
303 typedef IntrinsicBase<T, Order> Base;
305 static T or_(typename Base::ValueType& aPtr, T aVal)
307 AutoRecordAtomicAccess<Recording> record(&aPtr);
308 return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder);
311 static T xor_(typename Base::ValueType& aPtr, T aVal)
313 AutoRecordAtomicAccess<Recording> record(&aPtr);
314 return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder);
317 static T and_(typename Base::ValueType& aPtr, T aVal)
319 AutoRecordAtomicAccess<Recording> record(&aPtr);
320 return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder);
324 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
325 struct AtomicIntrinsics<T*, Order, Recording>
326 : public IntrinsicMemoryOps<T*, Order, Recording>,
327 public IntrinsicIncDec<T*, Order, Recording>
331 template<typename T>
332 struct ToStorageTypeArgument
334 static constexpr T convert (T aT) { return aT; }
337 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
338 class AtomicBase
340 static_assert(sizeof(T) == 4 || sizeof(T) == 8,
341 "mozilla/Atomics.h only supports 32-bit and 64-bit types");
343 protected:
344 typedef typename detail::AtomicIntrinsics<T, Order, Recording> Intrinsics;
345 typedef typename Intrinsics::ValueType ValueType;
346 ValueType mValue;
348 public:
349 constexpr AtomicBase() : mValue() {}
350 explicit constexpr AtomicBase(T aInit)
351 : mValue(ToStorageTypeArgument<T>::convert(aInit))
354 // Note: we can't provide operator T() here because Atomic<bool> inherits
355 // from AtomcBase with T=uint32_t and not T=bool. If we implemented
356 // operator T() here, it would cause errors when comparing Atomic<bool> with
357 // a regular bool.
359 T operator=(T aVal)
361 Intrinsics::store(mValue, aVal);
362 return aVal;
366 * Performs an atomic swap operation. aVal is stored and the previous
367 * value of this variable is returned.
369 T exchange(T aVal)
371 return Intrinsics::exchange(mValue, aVal);
375 * Performs an atomic compare-and-swap operation and returns true if it
376 * succeeded. This is equivalent to atomically doing
378 * if (mValue == aOldValue) {
379 * mValue = aNewValue;
380 * return true;
381 * } else {
382 * return false;
385 bool compareExchange(T aOldValue, T aNewValue)
387 return Intrinsics::compareExchange(mValue, aOldValue, aNewValue);
390 private:
391 AtomicBase(const AtomicBase& aCopy) = delete;
394 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
395 class AtomicBaseIncDec : public AtomicBase<T, Order, Recording>
397 typedef typename detail::AtomicBase<T, Order, Recording> Base;
399 public:
400 constexpr AtomicBaseIncDec() : Base() {}
401 explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {}
403 using Base::operator=;
405 operator T() const { return Base::Intrinsics::load(Base::mValue); }
406 T operator++(int) { return Base::Intrinsics::inc(Base::mValue); }
407 T operator--(int) { return Base::Intrinsics::dec(Base::mValue); }
408 T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; }
409 T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; }
411 private:
412 AtomicBaseIncDec(const AtomicBaseIncDec& aCopy) = delete;
415 } // namespace detail
418 * A wrapper for a type that enforces that all memory accesses are atomic.
420 * In general, where a variable |T foo| exists, |Atomic<T> foo| can be used in
421 * its place. Implementations for integral and pointer types are provided
422 * below.
424 * Atomic accesses are sequentially consistent by default. You should
425 * use the default unless you are tall enough to ride the
426 * memory-ordering roller coaster (if you're not sure, you aren't) and
427 * you have a compelling reason to do otherwise.
429 * There is one exception to the case of atomic memory accesses: providing an
430 * initial value of the atomic value is not guaranteed to be atomic. This is a
431 * deliberate design choice that enables static atomic variables to be declared
432 * without introducing extra static constructors.
434 template<typename T,
435 MemoryOrdering Order = SequentiallyConsistent,
436 recordreplay::Behavior Recording = recordreplay::Behavior::Preserve,
437 typename Enable = void>
438 class Atomic;
441 * Atomic<T> implementation for integral types.
443 * In addition to atomic store and load operations, compound assignment and
444 * increment/decrement operators are implemented which perform the
445 * corresponding read-modify-write operation atomically. Finally, an atomic
446 * swap method is provided.
448 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
449 class Atomic<T, Order, Recording,
450 typename EnableIf<IsIntegral<T>::value &&
451 !IsSame<T, bool>::value>::Type>
452 : public detail::AtomicBaseIncDec<T, Order, Recording>
454 typedef typename detail::AtomicBaseIncDec<T, Order, Recording> Base;
456 public:
457 constexpr Atomic() : Base() {}
458 explicit constexpr Atomic(T aInit) : Base(aInit) {}
460 using Base::operator=;
462 T operator+=(T aDelta)
464 return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
467 T operator-=(T aDelta)
469 return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
472 T operator|=(T aVal)
474 return Base::Intrinsics::or_(Base::mValue, aVal) | aVal;
477 T operator^=(T aVal)
479 return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal;
482 T operator&=(T aVal)
484 return Base::Intrinsics::and_(Base::mValue, aVal) & aVal;
487 private:
488 Atomic(Atomic& aOther) = delete;
492 * Atomic<T> implementation for pointer types.
494 * An atomic compare-and-swap primitive for pointer variables is provided, as
495 * are atomic increment and decement operators. Also provided are the compound
496 * assignment operators for addition and subtraction. Atomic swap (via
497 * exchange()) is included as well.
499 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
500 class Atomic<T*, Order, Recording> : public detail::AtomicBaseIncDec<T*, Order, Recording>
502 typedef typename detail::AtomicBaseIncDec<T*, Order, Recording> Base;
504 public:
505 constexpr Atomic() : Base() {}
506 explicit constexpr Atomic(T* aInit) : Base(aInit) {}
508 using Base::operator=;
510 T* operator+=(ptrdiff_t aDelta)
512 return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
515 T* operator-=(ptrdiff_t aDelta)
517 return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
520 private:
521 Atomic(Atomic& aOther) = delete;
525 * Atomic<T> implementation for enum types.
527 * The atomic store and load operations and the atomic swap method is provided.
529 template<typename T, MemoryOrdering Order, recordreplay::Behavior Recording>
530 class Atomic<T, Order, Recording, typename EnableIf<IsEnum<T>::value>::Type>
531 : public detail::AtomicBase<T, Order, Recording>
533 typedef typename detail::AtomicBase<T, Order, Recording> Base;
535 public:
536 constexpr Atomic() : Base() {}
537 explicit constexpr Atomic(T aInit) : Base(aInit) {}
539 operator T() const { return T(Base::Intrinsics::load(Base::mValue)); }
541 using Base::operator=;
543 private:
544 Atomic(Atomic& aOther) = delete;
548 * Atomic<T> implementation for boolean types.
550 * The atomic store and load operations and the atomic swap method is provided.
552 * Note:
554 * - sizeof(Atomic<bool>) != sizeof(bool) for some implementations of
555 * bool and/or some implementations of std::atomic. This is allowed in
556 * [atomic.types.generic]p9.
558 * - It's not obvious whether the 8-bit atomic functions on Windows are always
559 * inlined or not. If they are not inlined, the corresponding functions in the
560 * runtime library are not available on Windows XP. This is why we implement
561 * Atomic<bool> with an underlying type of uint32_t.
563 template<MemoryOrdering Order, recordreplay::Behavior Recording>
564 class Atomic<bool, Order, Recording>
565 : protected detail::AtomicBase<uint32_t, Order, Recording>
567 typedef typename detail::AtomicBase<uint32_t, Order, Recording> Base;
569 public:
570 constexpr Atomic() : Base() {}
571 explicit constexpr Atomic(bool aInit) : Base(aInit) {}
573 // We provide boolean wrappers for the underlying AtomicBase methods.
574 MOZ_IMPLICIT operator bool() const
576 return Base::Intrinsics::load(Base::mValue);
579 bool operator=(bool aVal)
581 return Base::operator=(aVal);
584 bool exchange(bool aVal)
586 return Base::exchange(aVal);
589 bool compareExchange(bool aOldValue, bool aNewValue)
591 return Base::compareExchange(aOldValue, aNewValue);
594 private:
595 Atomic(Atomic& aOther) = delete;
598 // If you want to atomically swap two atomic values, use exchange().
599 template<typename T, MemoryOrdering Order>
600 void
601 Swap(Atomic<T, Order>&, Atomic<T, Order>&) = delete;
603 } // namespace mozilla
605 #endif /* mozilla_Atomics_h */