Atomics.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  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/. */
  6. /*
  7. * Implements (almost always) lock-free atomic operations. The operations here
  8. * are a subset of that which can be found in C++11's <atomic> header, with a
  9. * different API to enforce consistent memory ordering constraints.
  10. *
  11. * Anyone caught using |volatile| for inter-thread memory safety needs to be
  12. * sent a copy of this header and the C++11 standard.
  13. */
  14. #ifndef mozilla_Atomics_h
  15. #define mozilla_Atomics_h
  16. #include "mozilla/Assertions.h"
  17. #include "mozilla/Attributes.h"
  18. #include "mozilla/Compiler.h"
  19. #include "mozilla/TypeTraits.h"
  20. #include <atomic>
  21. #include <stdint.h>
  22. namespace mozilla {
  23. /**
  24. * An enum of memory ordering possibilities for atomics.
  25. *
  26. * Memory ordering is the observable state of distinct values in memory.
  27. * (It's a separate concept from atomicity, which concerns whether an
  28. * operation can ever be observed in an intermediate state. Don't
  29. * conflate the two!) Given a sequence of operations in source code on
  30. * memory, it is *not* always the case that, at all times and on all
  31. * cores, those operations will appear to have occurred in that exact
  32. * sequence. First, the compiler might reorder that sequence, if it
  33. * thinks another ordering will be more efficient. Second, the CPU may
  34. * not expose so consistent a view of memory. CPUs will often perform
  35. * their own instruction reordering, above and beyond that performed by
  36. * the compiler. And each core has its own memory caches, and accesses
  37. * (reads and writes both) to "memory" may only resolve to out-of-date
  38. * cache entries -- not to the "most recently" performed operation in
  39. * some global sense. Any access to a value that may be used by
  40. * multiple threads, potentially across multiple cores, must therefore
  41. * have a memory ordering imposed on it, for all code on all
  42. * threads/cores to have a sufficiently coherent worldview.
  43. *
  44. * http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync and
  45. * http://en.cppreference.com/w/cpp/atomic/memory_order go into more
  46. * detail on all this, including examples of how each mode works.
  47. *
  48. * Note that for simplicity and practicality, not all of the modes in
  49. * C++11 are supported. The missing C++11 modes are either subsumed by
  50. * the modes we provide below, or not relevant for the CPUs we support
  51. * in Gecko. These three modes are confusing enough as it is!
  52. */
  53. enum MemoryOrdering {
  54. /*
  55. * Relaxed ordering is the simplest memory ordering: none at all.
  56. * When the result of a write is observed, nothing may be inferred
  57. * about other memory. Writes ostensibly performed "before" on the
  58. * writing thread may not yet be visible. Writes performed "after" on
  59. * the writing thread may already be visible, if the compiler or CPU
  60. * reordered them. (The latter can happen if reads and/or writes get
  61. * held up in per-processor caches.) Relaxed ordering means
  62. * operations can always use cached values (as long as the actual
  63. * updates to atomic values actually occur, correctly, eventually), so
  64. * it's usually the fastest sort of atomic access. For this reason,
  65. * *it's also the most dangerous kind of access*.
  66. *
  67. * Relaxed ordering is good for things like process-wide statistics
  68. * counters that don't need to be consistent with anything else, so
  69. * long as updates themselves are atomic. (And so long as any
  70. * observations of that value can tolerate being out-of-date -- if you
  71. * need some sort of up-to-date value, you need some sort of other
  72. * synchronizing operation.) It's *not* good for locks, mutexes,
  73. * reference counts, etc. that mediate access to other memory, or must
  74. * be observably consistent with other memory.
  75. *
  76. * x86 architectures don't take advantage of the optimization
  77. * opportunities that relaxed ordering permits. Thus it's possible
  78. * that using relaxed ordering will "work" on x86 but fail elsewhere
  79. * (ARM, say, which *does* implement non-sequentially-consistent
  80. * relaxed ordering semantics). Be extra-careful using relaxed
  81. * ordering if you can't easily test non-x86 architectures!
  82. */
  83. Relaxed,
  84. /*
  85. * When an atomic value is updated with ReleaseAcquire ordering, and
  86. * that new value is observed with ReleaseAcquire ordering, prior
  87. * writes (atomic or not) are also observable. What ReleaseAcquire
  88. * *doesn't* give you is any observable ordering guarantees for
  89. * ReleaseAcquire-ordered operations on different objects. For
  90. * example, if there are two cores that each perform ReleaseAcquire
  91. * operations on separate objects, each core may or may not observe
  92. * the operations made by the other core. The only way the cores can
  93. * be synchronized with ReleaseAcquire is if they both
  94. * ReleaseAcquire-access the same object. This implies that you can't
  95. * necessarily describe some global total ordering of ReleaseAcquire
  96. * operations.
  97. *
  98. * ReleaseAcquire ordering is good for (as the name implies) atomic
  99. * operations on values controlling ownership of things: reference
  100. * counts, mutexes, and the like. However, if you are thinking about
  101. * using these to implement your own locks or mutexes, you should take
  102. * a good, hard look at actual lock or mutex primitives first.
  103. */
  104. ReleaseAcquire,
  105. /*
  106. * When an atomic value is updated with SequentiallyConsistent
  107. * ordering, all writes observable when the update is observed, just
  108. * as with ReleaseAcquire ordering. But, furthermore, a global total
  109. * ordering of SequentiallyConsistent operations *can* be described.
  110. * For example, if two cores perform SequentiallyConsistent operations
  111. * on separate objects, one core will observably perform its update
  112. * (and all previous operations will have completed), then the other
  113. * core will observably perform its update (and all previous
  114. * operations will have completed). (Although those previous
  115. * operations aren't themselves ordered -- they could be intermixed,
  116. * or ordered if they occur on atomic values with ordering
  117. * requirements.) SequentiallyConsistent is the *simplest and safest*
  118. * ordering of atomic operations -- it's always as if one operation
  119. * happens, then another, then another, in some order -- and every
  120. * core observes updates to happen in that single order. Because it
  121. * has the most synchronization requirements, operations ordered this
  122. * way also tend to be slowest.
  123. *
  124. * SequentiallyConsistent ordering can be desirable when multiple
  125. * threads observe objects, and they all have to agree on the
  126. * observable order of changes to them. People expect
  127. * SequentiallyConsistent ordering, even if they shouldn't, when
  128. * writing code, atomic or otherwise. SequentiallyConsistent is also
  129. * the ordering of choice when designing lockless data structures. If
  130. * you don't know what order to use, use this one.
  131. */
  132. SequentiallyConsistent,
  133. };
  134. namespace detail {
  135. /*
  136. * We provide CompareExchangeFailureOrder to work around a bug in some
  137. * versions of GCC's <atomic> header. See bug 898491.
  138. */
  139. template<MemoryOrdering Order> struct AtomicOrderConstraints;
  140. template<>
  141. struct AtomicOrderConstraints<Relaxed>
  142. {
  143. static const std::memory_order AtomicRMWOrder = std::memory_order_relaxed;
  144. static const std::memory_order LoadOrder = std::memory_order_relaxed;
  145. static const std::memory_order StoreOrder = std::memory_order_relaxed;
  146. static const std::memory_order CompareExchangeFailureOrder =
  147. std::memory_order_relaxed;
  148. };
  149. template<>
  150. struct AtomicOrderConstraints<ReleaseAcquire>
  151. {
  152. static const std::memory_order AtomicRMWOrder = std::memory_order_acq_rel;
  153. static const std::memory_order LoadOrder = std::memory_order_acquire;
  154. static const std::memory_order StoreOrder = std::memory_order_release;
  155. static const std::memory_order CompareExchangeFailureOrder =
  156. std::memory_order_acquire;
  157. };
  158. template<>
  159. struct AtomicOrderConstraints<SequentiallyConsistent>
  160. {
  161. static const std::memory_order AtomicRMWOrder = std::memory_order_seq_cst;
  162. static const std::memory_order LoadOrder = std::memory_order_seq_cst;
  163. static const std::memory_order StoreOrder = std::memory_order_seq_cst;
  164. static const std::memory_order CompareExchangeFailureOrder =
  165. std::memory_order_seq_cst;
  166. };
  167. template<typename T, MemoryOrdering Order>
  168. struct IntrinsicBase
  169. {
  170. typedef std::atomic<T> ValueType;
  171. typedef AtomicOrderConstraints<Order> OrderedOp;
  172. };
  173. template<typename T, MemoryOrdering Order>
  174. struct IntrinsicMemoryOps : public IntrinsicBase<T, Order>
  175. {
  176. typedef IntrinsicBase<T, Order> Base;
  177. static T load(const typename Base::ValueType& aPtr)
  178. {
  179. return aPtr.load(Base::OrderedOp::LoadOrder);
  180. }
  181. static void store(typename Base::ValueType& aPtr, T aVal)
  182. {
  183. aPtr.store(aVal, Base::OrderedOp::StoreOrder);
  184. }
  185. static T exchange(typename Base::ValueType& aPtr, T aVal)
  186. {
  187. return aPtr.exchange(aVal, Base::OrderedOp::AtomicRMWOrder);
  188. }
  189. static bool compareExchange(typename Base::ValueType& aPtr,
  190. T aOldVal, T aNewVal)
  191. {
  192. return aPtr.compare_exchange_strong(aOldVal, aNewVal,
  193. Base::OrderedOp::AtomicRMWOrder,
  194. Base::OrderedOp::CompareExchangeFailureOrder);
  195. }
  196. };
  197. template<typename T, MemoryOrdering Order>
  198. struct IntrinsicAddSub : public IntrinsicBase<T, Order>
  199. {
  200. typedef IntrinsicBase<T, Order> Base;
  201. static T add(typename Base::ValueType& aPtr, T aVal)
  202. {
  203. return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
  204. }
  205. static T sub(typename Base::ValueType& aPtr, T aVal)
  206. {
  207. return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
  208. }
  209. };
  210. template<typename T, MemoryOrdering Order>
  211. struct IntrinsicAddSub<T*, Order> : public IntrinsicBase<T*, Order>
  212. {
  213. typedef IntrinsicBase<T*, Order> Base;
  214. static T* add(typename Base::ValueType& aPtr, ptrdiff_t aVal)
  215. {
  216. return aPtr.fetch_add(aVal, Base::OrderedOp::AtomicRMWOrder);
  217. }
  218. static T* sub(typename Base::ValueType& aPtr, ptrdiff_t aVal)
  219. {
  220. return aPtr.fetch_sub(aVal, Base::OrderedOp::AtomicRMWOrder);
  221. }
  222. };
  223. template<typename T, MemoryOrdering Order>
  224. struct IntrinsicIncDec : public IntrinsicAddSub<T, Order>
  225. {
  226. typedef IntrinsicBase<T, Order> Base;
  227. static T inc(typename Base::ValueType& aPtr)
  228. {
  229. return IntrinsicAddSub<T, Order>::add(aPtr, 1);
  230. }
  231. static T dec(typename Base::ValueType& aPtr)
  232. {
  233. return IntrinsicAddSub<T, Order>::sub(aPtr, 1);
  234. }
  235. };
  236. template<typename T, MemoryOrdering Order>
  237. struct AtomicIntrinsics : public IntrinsicMemoryOps<T, Order>,
  238. public IntrinsicIncDec<T, Order>
  239. {
  240. typedef IntrinsicBase<T, Order> Base;
  241. static T or_(typename Base::ValueType& aPtr, T aVal)
  242. {
  243. return aPtr.fetch_or(aVal, Base::OrderedOp::AtomicRMWOrder);
  244. }
  245. static T xor_(typename Base::ValueType& aPtr, T aVal)
  246. {
  247. return aPtr.fetch_xor(aVal, Base::OrderedOp::AtomicRMWOrder);
  248. }
  249. static T and_(typename Base::ValueType& aPtr, T aVal)
  250. {
  251. return aPtr.fetch_and(aVal, Base::OrderedOp::AtomicRMWOrder);
  252. }
  253. };
  254. template<typename T, MemoryOrdering Order>
  255. struct AtomicIntrinsics<T*, Order>
  256. : public IntrinsicMemoryOps<T*, Order>, public IntrinsicIncDec<T*, Order>
  257. {
  258. };
  259. template<typename T>
  260. struct ToStorageTypeArgument
  261. {
  262. static constexpr T convert (T aT) { return aT; }
  263. };
  264. template<typename T, MemoryOrdering Order>
  265. class AtomicBase
  266. {
  267. static_assert(sizeof(T) == 4 || sizeof(T) == 8,
  268. "mozilla/Atomics.h only supports 32-bit and 64-bit types");
  269. protected:
  270. typedef typename detail::AtomicIntrinsics<T, Order> Intrinsics;
  271. typedef typename Intrinsics::ValueType ValueType;
  272. ValueType mValue;
  273. public:
  274. constexpr AtomicBase() : mValue() {}
  275. explicit constexpr AtomicBase(T aInit)
  276. : mValue(ToStorageTypeArgument<T>::convert(aInit))
  277. {}
  278. // Note: we can't provide operator T() here because Atomic<bool> inherits
  279. // from AtomcBase with T=uint32_t and not T=bool. If we implemented
  280. // operator T() here, it would cause errors when comparing Atomic<bool> with
  281. // a regular bool.
  282. T operator=(T aVal)
  283. {
  284. Intrinsics::store(mValue, aVal);
  285. return aVal;
  286. }
  287. /**
  288. * Performs an atomic swap operation. aVal is stored and the previous
  289. * value of this variable is returned.
  290. */
  291. T exchange(T aVal)
  292. {
  293. return Intrinsics::exchange(mValue, aVal);
  294. }
  295. /**
  296. * Performs an atomic compare-and-swap operation and returns true if it
  297. * succeeded. This is equivalent to atomically doing
  298. *
  299. * if (mValue == aOldValue) {
  300. * mValue = aNewValue;
  301. * return true;
  302. * } else {
  303. * return false;
  304. * }
  305. */
  306. bool compareExchange(T aOldValue, T aNewValue)
  307. {
  308. return Intrinsics::compareExchange(mValue, aOldValue, aNewValue);
  309. }
  310. private:
  311. template<MemoryOrdering AnyOrder>
  312. AtomicBase(const AtomicBase<T, AnyOrder>& aCopy) = delete;
  313. };
  314. template<typename T, MemoryOrdering Order>
  315. class AtomicBaseIncDec : public AtomicBase<T, Order>
  316. {
  317. typedef typename detail::AtomicBase<T, Order> Base;
  318. public:
  319. constexpr AtomicBaseIncDec() : Base() {}
  320. explicit constexpr AtomicBaseIncDec(T aInit) : Base(aInit) {}
  321. using Base::operator=;
  322. operator T() const { return Base::Intrinsics::load(Base::mValue); }
  323. T operator++(int) { return Base::Intrinsics::inc(Base::mValue); }
  324. T operator--(int) { return Base::Intrinsics::dec(Base::mValue); }
  325. T operator++() { return Base::Intrinsics::inc(Base::mValue) + 1; }
  326. T operator--() { return Base::Intrinsics::dec(Base::mValue) - 1; }
  327. private:
  328. template<MemoryOrdering AnyOrder>
  329. AtomicBaseIncDec(const AtomicBaseIncDec<T, AnyOrder>& aCopy) = delete;
  330. };
  331. } // namespace detail
  332. /**
  333. * A wrapper for a type that enforces that all memory accesses are atomic.
  334. *
  335. * In general, where a variable |T foo| exists, |Atomic<T> foo| can be used in
  336. * its place. Implementations for integral and pointer types are provided
  337. * below.
  338. *
  339. * Atomic accesses are sequentially consistent by default. You should
  340. * use the default unless you are tall enough to ride the
  341. * memory-ordering roller coaster (if you're not sure, you aren't) and
  342. * you have a compelling reason to do otherwise.
  343. *
  344. * There is one exception to the case of atomic memory accesses: providing an
  345. * initial value of the atomic value is not guaranteed to be atomic. This is a
  346. * deliberate design choice that enables static atomic variables to be declared
  347. * without introducing extra static constructors.
  348. */
  349. template<typename T,
  350. MemoryOrdering Order = SequentiallyConsistent,
  351. typename Enable = void>
  352. class Atomic;
  353. /**
  354. * Atomic<T> implementation for integral types.
  355. *
  356. * In addition to atomic store and load operations, compound assignment and
  357. * increment/decrement operators are implemented which perform the
  358. * corresponding read-modify-write operation atomically. Finally, an atomic
  359. * swap method is provided.
  360. */
  361. template<typename T, MemoryOrdering Order>
  362. class Atomic<T, Order, typename EnableIf<IsIntegral<T>::value &&
  363. !IsSame<T, bool>::value>::Type>
  364. : public detail::AtomicBaseIncDec<T, Order>
  365. {
  366. typedef typename detail::AtomicBaseIncDec<T, Order> Base;
  367. public:
  368. constexpr Atomic() : Base() {}
  369. explicit constexpr Atomic(T aInit) : Base(aInit) {}
  370. using Base::operator=;
  371. T operator+=(T aDelta)
  372. {
  373. return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
  374. }
  375. T operator-=(T aDelta)
  376. {
  377. return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
  378. }
  379. T operator|=(T aVal)
  380. {
  381. return Base::Intrinsics::or_(Base::mValue, aVal) | aVal;
  382. }
  383. T operator^=(T aVal)
  384. {
  385. return Base::Intrinsics::xor_(Base::mValue, aVal) ^ aVal;
  386. }
  387. T operator&=(T aVal)
  388. {
  389. return Base::Intrinsics::and_(Base::mValue, aVal) & aVal;
  390. }
  391. private:
  392. Atomic(Atomic<T, Order>& aOther) = delete;
  393. };
  394. /**
  395. * Atomic<T> implementation for pointer types.
  396. *
  397. * An atomic compare-and-swap primitive for pointer variables is provided, as
  398. * are atomic increment and decement operators. Also provided are the compound
  399. * assignment operators for addition and subtraction. Atomic swap (via
  400. * exchange()) is included as well.
  401. */
  402. template<typename T, MemoryOrdering Order>
  403. class Atomic<T*, Order> : public detail::AtomicBaseIncDec<T*, Order>
  404. {
  405. typedef typename detail::AtomicBaseIncDec<T*, Order> Base;
  406. public:
  407. constexpr Atomic() : Base() {}
  408. explicit constexpr Atomic(T* aInit) : Base(aInit) {}
  409. using Base::operator=;
  410. T* operator+=(ptrdiff_t aDelta)
  411. {
  412. return Base::Intrinsics::add(Base::mValue, aDelta) + aDelta;
  413. }
  414. T* operator-=(ptrdiff_t aDelta)
  415. {
  416. return Base::Intrinsics::sub(Base::mValue, aDelta) - aDelta;
  417. }
  418. private:
  419. Atomic(Atomic<T*, Order>& aOther) = delete;
  420. };
  421. /**
  422. * Atomic<T> implementation for enum types.
  423. *
  424. * The atomic store and load operations and the atomic swap method is provided.
  425. */
  426. template<typename T, MemoryOrdering Order>
  427. class Atomic<T, Order, typename EnableIf<IsEnum<T>::value>::Type>
  428. : public detail::AtomicBase<T, Order>
  429. {
  430. typedef typename detail::AtomicBase<T, Order> Base;
  431. public:
  432. constexpr Atomic() : Base() {}
  433. explicit constexpr Atomic(T aInit) : Base(aInit) {}
  434. operator T() const { return T(Base::Intrinsics::load(Base::mValue)); }
  435. using Base::operator=;
  436. private:
  437. Atomic(Atomic<T, Order>& aOther) = delete;
  438. };
  439. /**
  440. * Atomic<T> implementation for boolean types.
  441. *
  442. * The atomic store and load operations and the atomic swap method is provided.
  443. *
  444. * Note:
  445. *
  446. * - sizeof(Atomic<bool>) != sizeof(bool) for some implementations of
  447. * bool and/or some implementations of std::atomic. This is allowed in
  448. * [atomic.types.generic]p9.
  449. *
  450. * - It's not obvious whether the 8-bit atomic functions on Windows are always
  451. * inlined or not. If they are not inlined, the corresponding functions in the
  452. * runtime library are not available on Windows XP. This is why we implement
  453. * Atomic<bool> with an underlying type of uint32_t.
  454. */
  455. template<MemoryOrdering Order>
  456. class Atomic<bool, Order>
  457. : protected detail::AtomicBase<uint32_t, Order>
  458. {
  459. typedef typename detail::AtomicBase<uint32_t, Order> Base;
  460. public:
  461. constexpr Atomic() : Base() {}
  462. explicit constexpr Atomic(bool aInit) : Base(aInit) {}
  463. // We provide boolean wrappers for the underlying AtomicBase methods.
  464. MOZ_IMPLICIT operator bool() const
  465. {
  466. return Base::Intrinsics::load(Base::mValue);
  467. }
  468. bool operator=(bool aVal)
  469. {
  470. return Base::operator=(aVal);
  471. }
  472. bool exchange(bool aVal)
  473. {
  474. return Base::exchange(aVal);
  475. }
  476. bool compareExchange(bool aOldValue, bool aNewValue)
  477. {
  478. return Base::compareExchange(aOldValue, aNewValue);
  479. }
  480. private:
  481. Atomic(Atomic<bool, Order>& aOther) = delete;
  482. };
  483. } // namespace mozilla
  484. #endif /* mozilla_Atomics_h */