Honeycomb  0.1
Component-Model Framework
Atomic.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Core/Core.h"
5 
6 namespace honey
7 {
9 namespace atomic
10 {
11 
13 
23 enum class Order
24 {
25  relaxed,
26  consume,
27  acquire,
28  release,
29  acqRel,
30  seqCst
31 };
32 
33 } }
34 
35 #include "Honey/Thread/platform/Atomic.h"
36 
37 namespace honey
38 {
39 
40 namespace atomic
41 {
43  class Op : platform::Op
44  {
45  typedef platform::Op Super;
46  public:
47 
49  template<class T>
50  static T load(volatile const T& val, Order o = Order::seqCst) { return Super::load(val, o); }
51  using Super::load;
52 
54  template<class T>
55  static void store(volatile T& dst, T newVal, Order o = Order::seqCst) { return Super::store(dst, newVal, o); }
56  using Super::store;
57 
59  template<class T>
60  static bool cas(volatile T& dst, T newVal, T cmp, Order o = Order::seqCst) { return Super::cas(dst, newVal, cmp, o); }
61 
63  template<class T>
64  static T swap(volatile T& dst, T newVal, Order o = Order::seqCst) { T v; do { v = dst; } while (!cas(dst, newVal, v, o)); return v; }
65  using Super::swap;
66 
68  template<class T>
69  static T inc(volatile T& val, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v+1, v, o)); return v; }
70  using Super::inc;
71 
73  template<class T>
74  static T dec(volatile T& val, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v-1, v, o)); return v; }
75  using Super::dec;
76 
78  template<class T>
79  static T add(volatile T& val, T rhs, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v+rhs, v, o)); return v; }
80 
82  template<class T>
83  static T and_(volatile T& val, T rhs, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v&rhs, v, o)); return v; }
84 
86  template<class T>
87  static T or_(volatile T& val, T rhs, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v|rhs, v, o)); return v; }
88 
90  template<class T>
91  static T xor_(volatile T& val, T rhs, Order o = Order::seqCst) { T v; do { v = val; } while (!cas(val, v^rhs, v, o)); return v; }
92 
94 
101  static void fence(Order o = Order::seqCst) { Super::fence(o); }
102  };
103 
106 
108  template<class T> struct SwapType
109  {
110  static_assert(sizeof(T) <= sizeof(SwapMaxType), "Type too large for atomic ops");
111  typedef typename std::conditional<
112  sizeof(T) <= sizeof(int32), int32,
113  typename std::conditional<sizeof(T) <= sizeof(int64), int64, SwapMaxType>::type
114  >::type type;
115  };
116 }
117 
118 template<class T, bool B = std::is_integral<T>::value>
119 class Atomic;
120 
122 template<class T>
123 class Atomic<T, false>
124 {
125  typedef typename atomic::SwapType<T>::type SwapType;
126  typedef atomic::Order Order;
127  typedef atomic::Op Op;
128 
129  //holds a T object in a SwapType value
130  struct SwapVal
131  {
132  SwapVal(T val) { new (&this->val) T(val); }
133  SwapType val;
134  };
135 
136 public:
137  static_assert(std::is_trivially_copyable<T>::value, "Atomic type must be trivially copyable");
138 
140  Atomic() = default;
142  Atomic(T val) { operator=(val); }
143  Atomic(const Atomic& val) { operator=(val); }
144 
146  T operator=(T val) volatile { store(val); return *this; }
147  T operator=(const Atomic& val) volatile { store(val); return *this; }
148 
150  operator T() const volatile { return load(); }
151 
152  void store(T val, Order o = Order::seqCst) volatile { Op::store(_val, SwapVal(val).val, o); }
153  T load(Order o = Order::seqCst) const volatile { auto ret = Op::load(_val, o); return reinterpret_cast<T&>(ret); }
154 
156  bool cas(T newVal, T cmp, Order o = Order::seqCst) volatile { return Op::cas(_val, SwapVal(newVal).val, SwapVal(cmp).val, o); }
157 
158 private:
159  SwapType _val;
160 };
161 
163 template<class T>
164 class Atomic<T, true>
165 {
166  typedef typename atomic::SwapType<T>::type SwapType;
167  typedef atomic::Order Order;
168  typedef atomic::Op Op;
169 
170 public:
171  Atomic() = default;
172  Atomic(T val) { operator=(val); }
173  Atomic(const Atomic& val) { operator=(val); }
174 
176  T operator=(T val) volatile { store(val); return *this; }
177  T operator=(const Atomic& val) volatile { store(val); return *this; }
178 
180  T operator++() volatile { return Op::inc(_val) + 1; }
182  T operator++(int) volatile { return Op::inc(_val); }
184  T operator--() volatile { return Op::dec(_val) - 1; }
186  T operator--(int) volatile { return Op::dec(_val); }
188  T operator+=(T rhs) volatile { return add(rhs); }
190  T operator-=(T rhs) volatile { return sub(rhs); }
192  T operator&=(T rhs) volatile { return and_(rhs); }
194  T operator|=(T rhs) volatile { return or_(rhs); }
196  T operator^=(T rhs) volatile { return xor_(rhs); }
197 
199  operator T() const volatile { return load(); }
200 
201  void store(T val, Order o = Order::seqCst) volatile { Op::store(_val, static_cast<SwapType>(val), o); }
202  T load(Order o = Order::seqCst) const volatile { return static_cast<T>(Op::load(_val, o)); }
203  T add(T rhs, Order o = Order::seqCst) volatile { return Op::add(_val, static_cast<SwapType>(rhs), o) + rhs; }
204  T sub(T rhs, Order o = Order::seqCst) volatile { return Op::add(_val, static_cast<SwapType>(-rhs), o) - rhs; }
205  T and_(T rhs, Order o = Order::seqCst) volatile { return Op::and_(_val, static_cast<SwapType>(rhs), o) & rhs; }
206  T or_(T rhs, Order o = Order::seqCst) volatile { return Op::or_(_val, static_cast<SwapType>(rhs), o) | rhs; }
207  T xor_(T rhs, Order o = Order::seqCst) volatile { return Op::xor_(_val, static_cast<SwapType>(rhs), o) ^ rhs; }
208 
210  bool cas(T newVal, T cmp, Order o = Order::seqCst) volatile { return Op::cas(_val, static_cast<SwapType>(newVal), static_cast<SwapType>(cmp), o); }
211 
212 private:
213  SwapType _val;
214 };
215 
217 template<class T>
218 class Atomic<T*, false>
219 {
220  typedef typename atomic::SwapType<T*>::type SwapType;
221  typedef atomic::Order Order;
222  typedef atomic::Op Op;
223 
224 public:
225  Atomic() = default;
226  Atomic(T* val) { operator=(val); }
227  Atomic(const Atomic& val) { operator=(val); }
228 
229  T* operator=(T* val) volatile { store(val); return *this; }
230  T* operator=(const Atomic& val) volatile { store(val); return *this; }
231 
232  T* operator++() volatile { return reinterpret_cast<T*>(Op::add(_val, sizeof(T))) + 1; }
233  T* operator++(int) volatile { return reinterpret_cast<T*>(Op::add(_val, sizeof(T))); }
234  T* operator--() volatile { return reinterpret_cast<T*>(Op::add(_val, -sizeof(T))) - 1; }
235  T* operator--(int) volatile { return reinterpret_cast<T*>(Op::add(_val, -sizeof(T))); }
236  T* operator+=(sdt rhs) volatile { return add(rhs); }
237  T* operator-=(sdt rhs) volatile { return sub(rhs); }
238 
239  T* operator->() const volatile { return load(); }
240  T& operator*() const volatile { return *load(); }
241  operator T*() const volatile { return load(); }
242 
243  void store(T* val, Order o = Order::seqCst) volatile { Op::store(_val, reinterpret_cast<SwapType>(val), o); }
244  T* load(Order o = Order::seqCst) const volatile { return reinterpret_cast<T*>(Op::load(_val, o)); }
245  T* add(sdt rhs, Order o = Order::seqCst) volatile { return reinterpret_cast<T*>(Op::add(_val, rhs*sizeof(T), o)) + rhs; }
246  T* sub(sdt rhs, Order o = Order::seqCst) volatile { return reinterpret_cast<T*>(Op::add(_val, -rhs*sizeof(T), o)) - rhs; }
247 
248  bool cas(T* newVal, T* cmp, Order o = Order::seqCst) volatile { return Op::cas(_val, reinterpret_cast<SwapType>(newVal), reinterpret_cast<SwapType>(cmp), o); }
249 
250 private:
251  SwapType _val;
252 };
253 
255 template<class T>
256 ostream& operator<<(ostream& os, const Atomic<T>& val) { return os << val.load(); }
257 
258 }
T operator++(int) volatile
Post-increment, returns initial value.
Definition: Atomic.h:182
void store(T *val, Order o=Order::seqCst) volatile
Definition: Atomic.h:243
static bool cas(volatile T &dst, T newVal, T cmp, Order o=Order::seqCst)
Compare and swap. If dst is equal to comparand cmp then dst is assigned to newVal and true is returne...
Definition: Atomic.h:60
Atomic(const Atomic &val)
Definition: Atomic.h:227
T operator&=(T rhs) volatile
And and return new value.
Definition: Atomic.h:192
static T xor_(volatile T &val, T rhs, Order o=Order::seqCst)
val ^= rhs. Returns the initial value.
Definition: Atomic.h:91
static T add(volatile T &val, T rhs, Order o=Order::seqCst)
val += rhs. Returns the initial value.
Definition: Atomic.h:79
ptrdiff_t sdt
Size difference type, shorthand for ptrdiff_t.
Definition: Core.h:92
T operator=(T val) volatile
Assign value.
Definition: Atomic.h:176
static T and_(volatile T &val, T rhs, Order o=Order::seqCst)
val &= rhs. Returns the initial value.
Definition: Atomic.h:83
T operator+=(T rhs) volatile
Add and return new value.
Definition: Atomic.h:188
bool cas(T newVal, T cmp, Order o=Order::seqCst) volatile
Compare and swap. If atomic is equal to comparand cmp then atomic is assigned to newVal and true is r...
Definition: Atomic.h:210
Methods to perform thread-safe atomic read/write operations.
Definition: Atomic.h:43
T * operator=(T *val) volatile
Definition: Atomic.h:229
T load(Order o=Order::seqCst) const volatile
Definition: Atomic.h:153
T * operator+=(sdt rhs) volatile
Definition: Atomic.h:236
Must be a store op. Synchronize with a later acquire in another thread.
Order
Atomic memory order for concurrent synchronization between threads.
Definition: Atomic.h:23
T operator++() volatile
Pre-increment, returns new value.
Definition: Atomic.h:180
T operator--(int) volatile
Post-decrement, returns initial value.
Definition: Atomic.h:186
ostream & dec(ostream &os)
Use decimal encoding (big-endian integer) when writing bytes to a string stream.
Definition: Encode.h:66
T operator=(T val) volatile
Assign value.
Definition: Atomic.h:146
T * load(Order o=Order::seqCst) const volatile
Definition: Atomic.h:244
Definition: Atomic.h:119
T add(T rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:203
T * add(sdt rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:245
T operator=(const Atomic &val) volatile
Definition: Atomic.h:177
Must be a load op. Synchronize with a prior release in another thread.
T operator|=(T rhs) volatile
Or and return new value.
Definition: Atomic.h:194
static T inc(volatile T &val, Order o=Order::seqCst)
Increments val. Returns the initial value.
Definition: Atomic.h:69
T xor_(T rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:207
Get the smallest atomically-swappable type that is large enough to hold T.
Definition: Atomic.h:108
void store(T val, Order o=Order::seqCst) volatile
Definition: Atomic.h:152
T sub(T rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:204
Atomic(const Atomic &val)
Definition: Atomic.h:173
No order constraint, same as plain load/store. Unsafe but best performance.
int int32
Definition: Core.h:15
static void fence(Order o=Order::seqCst)
Create a memory barrier that synchronizes operations.
Definition: Atomic.h:101
Atomic(T val)
Definition: Atomic.h:172
Atomic(const Atomic &val)
Definition: Atomic.h:143
T operator-=(T rhs) volatile
Sub and return new value.
Definition: Atomic.h:190
static T load(volatile const T &val, Order o=Order::seqCst)
Returns val.
Definition: Atomic.h:50
T load(Order o=Order::seqCst) const volatile
Definition: Atomic.h:202
T * operator++(int) volatile
Definition: Atomic.h:233
T * operator->() const volatile
Definition: Atomic.h:239
T and_(T rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:205
static T or_(volatile T &val, T rhs, Order o=Order::seqCst)
val |= rhs. Returns the initial value.
Definition: Atomic.h:87
T * sub(sdt rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:246
Atomic(T *val)
Definition: Atomic.h:226
bool cas(T *newVal, T *cmp, Order o=Order::seqCst) volatile
Definition: Atomic.h:248
void store(T val, Order o=Order::seqCst) volatile
Definition: Atomic.h:201
bool cas(T newVal, T cmp, Order o=Order::seqCst) volatile
Compare and swap. If atomic is equal to comparand cmp then atomic is assigned to newVal and true is r...
Definition: Atomic.h:156
static T swap(volatile T &dst, T newVal, Order o=Order::seqCst)
Assigns dst to newVal and returns initial value of dst.
Definition: Atomic.h:64
#define swap(a, i, j)
T * operator=(const Atomic &val) volatile
Definition: Atomic.h:230
Op
Definition: Unique.h:16
Sequential consistency, safe total order but least performance.
Atomic(T val)
Initialize the underlying value to val
Definition: Atomic.h:142
static void store(volatile T &dst, T newVal, Order o=Order::seqCst)
Assigns dst to newVal.
Definition: Atomic.h:55
Must be a load op. Synchronize with a prior release in another thread, but only synchronize ops depen...
T & operator*() const volatile
Definition: Atomic.h:240
Must be a load-modify-store op. Performs both acquire and release.
T operator^=(T rhs) volatile
Xor and return new value.
Definition: Atomic.h:196
T operator=(const Atomic &val) volatile
Definition: Atomic.h:147
T * operator++() volatile
Definition: Atomic.h:232
T * operator--(int) volatile
Definition: Atomic.h:235
T * operator-=(sdt rhs) volatile
Definition: Atomic.h:237
T * operator--() volatile
Definition: Atomic.h:234
platform::SwapMaxType SwapMaxType
Largest atomically-swappable type.
Definition: Atomic.h:105
Global Honeycomb namespace.
static T dec(volatile T &val, Order o=Order::seqCst)
Decrements val. Returns the initial value.
Definition: Atomic.h:74
T operator--() volatile
Pre-decrement, returns new value.
Definition: Atomic.h:184
T or_(T rhs, Order o=Order::seqCst) volatile
Definition: Atomic.h:206