1 | // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_PLATFORM_ATOMIC_H_ |
6 | #define RUNTIME_PLATFORM_ATOMIC_H_ |
7 | |
8 | #include <atomic> |
9 | |
10 | namespace dart { |
11 | |
12 | // Like std::atomic, but operations default to relaxed ordering instead of |
13 | // sequential consistency. |
14 | template <typename T> |
15 | class RelaxedAtomic { |
16 | public: |
17 | constexpr RelaxedAtomic() : value_() {} |
18 | constexpr RelaxedAtomic(T arg) : value_(arg) {} // NOLINT |
19 | RelaxedAtomic(const RelaxedAtomic& arg) : value_(arg) {} // NOLINT |
20 | |
21 | T load(std::memory_order order = std::memory_order_relaxed) const { |
22 | return value_.load(order); |
23 | } |
24 | void store(T arg, std::memory_order order = std::memory_order_relaxed) { |
25 | value_.store(arg, order); |
26 | } |
27 | |
28 | T fetch_add(T arg, std::memory_order order = std::memory_order_relaxed) { |
29 | return value_.fetch_add(arg, order); |
30 | } |
31 | T fetch_sub(T arg, std::memory_order order = std::memory_order_relaxed) { |
32 | return value_.fetch_sub(arg, order); |
33 | } |
34 | T fetch_or(T arg, std::memory_order order = std::memory_order_relaxed) { |
35 | return value_.fetch_or(arg, order); |
36 | } |
37 | T fetch_and(T arg, std::memory_order order = std::memory_order_relaxed) { |
38 | return value_.fetch_and(arg, order); |
39 | } |
40 | |
41 | bool compare_exchange_weak( |
42 | T& expected, // NOLINT |
43 | T desired, |
44 | std::memory_order order = std::memory_order_relaxed) { |
45 | return value_.compare_exchange_weak(expected, desired, order, order); |
46 | } |
47 | bool compare_exchange_strong( |
48 | T& expected, // NOLINT |
49 | T desired, |
50 | std::memory_order order = std::memory_order_relaxed) { |
51 | return value_.compare_exchange_strong(expected, desired, order, order); |
52 | } |
53 | |
54 | operator T() const { return load(); } |
55 | T operator=(T arg) { |
56 | store(arg); |
57 | return arg; |
58 | } |
59 | T operator=(const RelaxedAtomic& arg) { |
60 | T loaded_once = arg; |
61 | store(loaded_once); |
62 | return loaded_once; |
63 | } |
64 | T operator+=(T arg) { return fetch_add(arg) + arg; } |
65 | T operator-=(T arg) { return fetch_sub(arg) - arg; } |
66 | |
67 | private: |
68 | std::atomic<T> value_; |
69 | }; |
70 | |
71 | // Like std::atomic, but operations default to acquire for load, release for |
72 | // stores, and acquire-release for read-and-updates. |
73 | template <typename T> |
74 | class AcqRelAtomic { |
75 | public: |
76 | constexpr AcqRelAtomic() : value_() {} |
77 | constexpr AcqRelAtomic(T arg) : value_(arg) {} // NOLINT |
78 | AcqRelAtomic(const AcqRelAtomic& arg) = delete; |
79 | |
80 | T load(std::memory_order order = std::memory_order_acquire) const { |
81 | return value_.load(order); |
82 | } |
83 | void store(T arg, std::memory_order order = std::memory_order_release) { |
84 | value_.store(arg, order); |
85 | } |
86 | |
87 | T fetch_add(T arg, std::memory_order order = std::memory_order_acq_rel) { |
88 | return value_.fetch_add(arg, order); |
89 | } |
90 | T fetch_sub(T arg, std::memory_order order = std::memory_order_acq_rel) { |
91 | return value_.fetch_sub(arg, order); |
92 | } |
93 | T fetch_or(T arg, std::memory_order order = std::memory_order_acq_rel) { |
94 | return value_.fetch_or(arg, order); |
95 | } |
96 | T fetch_and(T arg, std::memory_order order = std::memory_order_acq_rel) { |
97 | return value_.fetch_and(arg, order); |
98 | } |
99 | |
100 | bool compare_exchange_weak( |
101 | T& expected, // NOLINT |
102 | T desired, |
103 | std::memory_order order = std::memory_order_acq_rel) { |
104 | return value_.compare_exchange_weak(expected, desired, order, order); |
105 | } |
106 | bool compare_exchange_strong( |
107 | T& expected, // NOLINT |
108 | T desired, |
109 | std::memory_order order = std::memory_order_acq_rel) { |
110 | return value_.compare_exchange_strong(expected, desired, order, order); |
111 | } |
112 | |
113 | // Require explicit loads and stores. |
114 | operator T() const = delete; |
115 | T operator=(T arg) = delete; |
116 | T operator=(const AcqRelAtomic& arg) = delete; |
117 | T operator+=(T arg) = delete; |
118 | T operator-=(T arg) = delete; |
119 | |
120 | private: |
121 | std::atomic<T> value_; |
122 | }; |
123 | |
124 | } // namespace dart |
125 | |
126 | #endif // RUNTIME_PLATFORM_ATOMIC_H_ |
127 | |