HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SYS_AtomicInt.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: SYS_AtomicInt.h (SYS Library, C++)
7  *
8  * COMMENTS: Thread-safe operations on integers
9  */
10 
11 #ifndef __SYS_AtomicInt__
12 #define __SYS_AtomicInt__
13 
14 #include "SYS_Types.h"
15 #include "SYS_MemoryOrder.h"
16 #include "SYS_AtomicImpl.h"
17 #include <SYS/SYS_TypeDecorate.h>
18 
19 #include <atomic>
20 
21 template <typename T>
23 {
24 public:
25  explicit SYS_AtomicInt(T value = 0) : myValue(value) {}
26 
27  /// An empty constructor. This will initialize the value with garbage,
28  /// unless used as a static object (in which case it will be guaranteed
29  /// by the C++ standard to be initialized to zero). Only use if required
30  /// to be set prior to other, dependent statically initialized objects.
32 
33  /// Atomically assigns val to myValue, returning the prior value of
34  /// myValue.
35  inline T exchange(T val);
36 
37  /// Atomically adds val to myValue, returning the prior value of
38  /// myValue.
39  inline T exchangeAdd(T val);
40 
41  /// Atomically adds val to myValue, returning the new value of myValue.
42  inline T add(T val);
43 
44  /// Atomically set myValue to the maximum of val and myValue. Returns the
45  /// last known maximal value.
46  inline T maximum(T val);
47 
48  /// Atomically set myValue to the minimum of val and myValue. Returns the
49  /// last known minimal value.
50  inline T minimum(T val);
51 
52  /// Atomically compares (myValue == expected), and if true, replaces
53  /// myValue with desired. Returns the prior value.
54  inline T compare_swap(T expected, T desired);
55 
56  inline bool compareExchangeStrong(
57  T &expected,
58  T desired,
61 
62  inline bool compareExchangeWeak(
63  T &expected,
64  T desired,
67 
68  /// @pre The supplied order must be one of [RELAXED, STORE, SEQ_CST].
70 
71  /// @pre The supplied order must be one of [RELAXED, LOAD, SEQ_CST].
73 
74  /// Forced RELAXED memory load
75  /// GCC has trouble inlining so we pull the definition up here.
77 
79 
80 private:
81  std::atomic<T> myValue;
82 
83 private:
84  // Prohibited operators
85  SYS_AtomicInt(const SYS_AtomicInt &) = default;
86  SYS_AtomicInt &operator=(const SYS_AtomicInt &) = default;
87  /// WARNING: DO NOT ADD THIS BACK! It was atomic, and nobody expected that,
88  /// so it ended up slowing down many things, including every
89  /// string attribute read.
90  explicit operator T() const;
91 
92  static constexpr std::memory_order sysToStdMemoryOrder(SYS_MemoryOrder order);
93 };
94 
97 
98 #if defined(AMD64) || defined(ARM64)
100 #else
102 #endif
103 
104 template <typename T>
106 
107 template <typename T>
110 {
111  return myValue.exchange(val);
112 }
113 
114 template <typename T>
117 {
118  return myValue.fetch_add(val);
119 }
120 
121 template <typename T>
124 {
125  return (myValue += val);
126 }
127 
128 template <typename T>
131 {
132  T me = relaxedLoad();
133 
134  do
135  {
136  if (me > val)
137  break;
138  }
139  while (!compareExchangeWeak(me, val));
140 
141  return me;
142 }
143 
144 template <typename T>
147 {
148  T me = relaxedLoad();
149 
150  do
151  {
152  if (me < val)
153  break;
154  }
155  while (!compareExchangeWeak(me, val));
156 
157  return me;
158 }
159 
160 template <typename T>
162 SYS_AtomicInt<T>::compare_swap(T expected, T desired)
163 {
164  compareExchangeStrong(expected, desired);
165  return expected;
166 }
167 
168 template <typename T>
171  T &expected,
172  T desired,
173  SYS_MemoryOrder success,
174  SYS_MemoryOrder failure)
175 {
176  return myValue.compare_exchange_strong(
177  expected, desired, sysToStdMemoryOrder(success),
178  sysToStdMemoryOrder(failure));
179 }
180 
181 template <typename T>
184  T &expected,
185  T desired,
186  SYS_MemoryOrder success,
187  SYS_MemoryOrder failure)
188 {
189  return myValue.compare_exchange_weak(
190  expected, desired, sysToStdMemoryOrder(success),
191  sysToStdMemoryOrder(failure));
192 }
193 
194 /// Next two methods intentionally not marked as volatile as this would cause
195 /// &myValue to evaluate to a pointer to a volatile myValue and that has
196 /// implications on MSVC2005+ beyond the C++ spec.
197 ///
198 /// This shouldn't be a problem unless somebody needs a volatile instance of
199 /// SYS_AtomicInt<T>.
200 template <typename T>
203 {
204  myValue.store(val, sysToStdMemoryOrder(order));
205 }
206 
207 template <typename T>
210 {
211  return myValue.load(sysToStdMemoryOrder(order));
212 }
213 
214 template <typename T>
217 {
218  return myValue.load(std::memory_order_relaxed);
219 }
220 
221 template <typename T>
224 {
225  myValue.store(val, std::memory_order_relaxed);
226 };
227 
228 template <typename T>
229 SYS_ATOMIC_INLINE constexpr std::memory_order
231 {
232  std::memory_order std_order = std::memory_order_seq_cst;
233 
234  switch (order)
235  {
236  case SYS_MEMORY_ORDER_RELAXED: std_order = std::memory_order_relaxed; break;
237  case SYS_MEMORY_ORDER_LOAD: std_order = std::memory_order_acquire; break;
238  case SYS_MEMORY_ORDER_STORE: std_order = std::memory_order_release; break;
239  case SYS_MEMORY_ORDER_SEQ_CST: std_order = std::memory_order_seq_cst; break;
240  }
241 
242  return std_order;
243 }
244 
245 #endif
#define SYS_DECLARE_LEGACY_TR_TEMPLATE(...)
Version for class template.
SYS_FORCE_INLINE void relaxedStore(T val)
SYS_AtomicInt(T value=0)
Definition: SYS_AtomicInt.h:25
SYS_AtomicInt< int32 > SYS_AtomicInt32
Definition: SYS_AtomicInt.h:95
void store(T val, SYS_MemoryOrder order=SYS_MEMORY_ORDER_SEQ_CST)
T exchange(T val)
SYS_AtomicInt(SYS_EmptyConstructor)
Definition: SYS_AtomicInt.h:31
T exchangeAdd(T val)
SYS_MemoryOrder
bool compareExchangeStrong(T &expected, T desired, SYS_MemoryOrder success=SYS_MEMORY_ORDER_SEQ_CST, SYS_MemoryOrder failure=SYS_MEMORY_ORDER_SEQ_CST)
SYS_EmptyConstructor
Definition: SYS_Types.h:435
T load(SYS_MemoryOrder order=SYS_MEMORY_ORDER_SEQ_CST) const
bool compareExchangeWeak(T &expected, T desired, SYS_MemoryOrder success=SYS_MEMORY_ORDER_SEQ_CST, SYS_MemoryOrder failure=SYS_MEMORY_ORDER_SEQ_CST)
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
#define SYS_ATOMIC_INLINE
T compare_swap(T expected, T desired)
SYS_AtomicInt< int64 > SYS_AtomicInt64
Definition: SYS_AtomicInt.h:96
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
Any reordering the compiler or hardware chooses to do is okay.
SYS_FORCE_INLINE T relaxedLoad() const
T minimum(T val)
SYS_AtomicInt< int32 > SYS_AtomicCounter
T maximum(T val)
VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange(T &obj, U &&newValue)
Definition: vulkan_raii.hpp:25
GLuint GLfloat * val
Definition: glcorearb.h:1608
T add(T val)
Atomically adds val to myValue, returning the new value of myValue.
Definition: core.h:1131