XRootD
XrdSysRAtomic.hh
Go to the documentation of this file.
1 #ifndef __XRDSYSRATOMIC__HH
2 #define __XRDSYSRATOMIC__HH
3 /******************************************************************************/
4 /* */
5 /* X r d S y s R A t o m i c . h h */
6 /* */
7 /******************************************************************************/
8 
9 /* The XrdSys::RAtomic class can be used to define an integral, pointer, or
10  boolean type atomic variable that use relaxed memory order by default. In
11  general all atomics should use relaxed memory order and when more than one
12  such variable needs to be synchronized these should be done using a lock.
13  The server/client architecture do not require nor should require multiple
14  variable ordering consistency in the presence of atomics. This is done to
15  make it clear which variable are co-dependent in terms of atomic access.
16 */
17 
18 #include <atomic>
19 #include <cstddef>
20 #include <cstdint>
21 
22 namespace XrdSys
23 {
24 template<typename T>
25 class RAtomic
26 {
27 public:
28 
29 // Store and fetch defined here for immediate expansion
30 //
31 T operator=(T v) noexcept
32  {_m.store(v, std::memory_order_relaxed); return v;}
33 
34 T operator=(T v) volatile noexcept
35  {_m.store(v, std::memory_order_relaxed); return v;}
36 
37  operator T() noexcept
38  {return _m.load(std::memory_order_relaxed);}
39 
40  operator T() const noexcept
41  {return _m.load(std::memory_order_relaxed);}
42 
43  operator T() volatile noexcept
44  {return _m.load(std::memory_order_relaxed);}
45 
46  operator T() const volatile noexcept
47  {return _m.load(std::memory_order_relaxed);}
48 
49  // Assignment operators
50 
51  RAtomic& operator=(const RAtomic& other) noexcept {
52  if (this != &other) {
53  _m.store(other._m.load(std::memory_order_relaxed), std::memory_order_relaxed);
54  }
55  return *this;
56  }
57 
58  RAtomic& operator=(const RAtomic& other) volatile noexcept {
59  if (this != &other) {
60  _m.store(other._m.load(std::memory_order_relaxed), std::memory_order_relaxed);
61  }
62  return *this;
63  }
64 
65 // Post-increment/decrement (i.e. x++)
66 //
67 T operator++(int) noexcept
68  {return _m.fetch_add(1, std::memory_order_relaxed);}
69 
70 T operator++(int) volatile noexcept
71  {return _m.fetch_add(1, std::memory_order_relaxed);}
72 
73 T operator--(int) noexcept
74  {return _m.fetch_sub(1, std::memory_order_relaxed);}
75 
76 T operator--(int) volatile noexcept
77  {return _m.fetch_sub(1, std::memory_order_relaxed);}
78 
79 // Pre-increment/decrement (i.e.++x)
80 //
81 T operator++() noexcept
82  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
83 
84 T operator++() volatile noexcept
85  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
86 
87 T operator--() noexcept
88  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
89 
90 T operator--() volatile noexcept
91  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
92 
93 T operator+=(T v) noexcept
94  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
95 
96 T operator+=(T v) volatile noexcept
97  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
98 
99 T operator-=(T v) noexcept
100  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
101 
102 T operator-=(T v) volatile noexcept
103  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
104 
105 T operator&=(T v) noexcept
106  {return _m.fetch_and(v, std::memory_order_relaxed) & v;}
107 
108 T operator&=(T v) volatile noexcept
109  {return _m.fetch_and(v, std::memory_order_relaxed) & v;}
110 
111 T operator|=(T v) noexcept
112  {return _m.fetch_or (v, std::memory_order_relaxed) | v;}
113 
114 T operator|=(T v) volatile noexcept
115  {return _m.fetch_or (v, std::memory_order_relaxed) | v;}
116 
117 T operator^=(T v) noexcept
118  {return _m.fetch_xor(v, std::memory_order_relaxed) ^ v;}
119 
120 T operator^=(T v) volatile noexcept
121  {return _m.fetch_xor(v, std::memory_order_relaxed) ^ v;}
122 
123 // Specialty functions that fetch and do a post operation
124 //
125 T fetch_and(T v) noexcept
126  {return _m.fetch_and(v, std::memory_order_relaxed);}
127 
128 T fetch_or(T v) noexcept
129  {return _m.fetch_or (v, std::memory_order_relaxed);}
130 
131 T fetch_xor(T v) noexcept
132  {return _m.fetch_xor(v, std::memory_order_relaxed);}
133 
134 // Member functions
135 //
137  std::memory_order mo1=std::memory_order_relaxed,
138  std::memory_order mo2=std::memory_order_relaxed)
139  noexcept
140  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
141 
143  std::memory_order mo1=std::memory_order_relaxed,
144  std::memory_order mo2=std::memory_order_relaxed)
145  volatile noexcept
146  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
147 
148 T compare_exchange_weak(T& v1, T v2,
149  std::memory_order mo1=std::memory_order_relaxed,
150  std::memory_order mo2=std::memory_order_relaxed)
151  noexcept
152  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
153 
154 T compare_exchange_weak(T& v1, T v2,
155  std::memory_order mo1=std::memory_order_relaxed,
156  std::memory_order mo2=std::memory_order_relaxed)
157  volatile noexcept
158  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
159 
160 T exchange(T v, std::memory_order mo=std::memory_order_relaxed) noexcept
161  {return _m.exchange(v, mo);}
162 
163 T exchange(T v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
164  {return _m.exchange(v, mo);}
165 
166  RAtomic() {}
167 
168  RAtomic(T v) : _m(v) {}
169 
170 private:
171 
172 std::atomic<T> _m;
173 };
174 
175 template<typename T>
176 class RAtomic<T*>
177 {
178 public:
179 
180 // Store and fetch defined here for immediate expansion
181 //
182 T* operator=(T* v) noexcept
183  {_m.store(v, std::memory_order_relaxed); return v;}
184 
185 T* operator=(T* v) volatile noexcept
186  {_m.store(v, std::memory_order_relaxed); return v;}
187 
188  operator T*() noexcept
189  {return _m.load(std::memory_order_relaxed);}
190 
191  operator T*() volatile noexcept
192  {return _m.load(std::memory_order_relaxed);}
193 
194  T* operator->() noexcept
195  {return _m.load(std::memory_order_relaxed);}
196 
197 // Post-increment/decrement (i.e. x++)
198 //
199 T* operator++(int) noexcept
200  {return _m.fetch_add(1, std::memory_order_relaxed);}
201 
202 T* operator++(int) volatile noexcept
203  {return _m.fetch_add(1, std::memory_order_relaxed);}
204 
205 T* operator--(int) noexcept
206  {return _m.fetch_sub(1, std::memory_order_relaxed);}
207 
208 T* operator--(int) volatile noexcept
209  {return _m.fetch_sub(1, std::memory_order_relaxed);}
210 
211 // Pre-increment/decrement (i.e.++x)
212 //
213 T* operator++() noexcept
214  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
215 
216 T* operator++() volatile noexcept
217  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
218 
219 T* operator--() noexcept
220  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
221 
222 T* operator--() volatile noexcept
223  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
224 
225 T* operator+=(ptrdiff_t v) noexcept
226  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
227 
228 T* operator+=(ptrdiff_t v) volatile noexcept
229  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
230 
231 T* operator-=(ptrdiff_t v) noexcept
232  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
233 
234 T* operator-=(ptrdiff_t v) volatile noexcept
235  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
236 
237 // Member functions
238 //
239 T* compare_exchange_strong(T& v1, T* v2,
240  std::memory_order mo1=std::memory_order_relaxed,
241  std::memory_order mo2=std::memory_order_relaxed)
242  noexcept
243  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
244 
245 T* compare_exchange_strong(T& v1, T* v2,
246  std::memory_order mo1=std::memory_order_relaxed,
247  std::memory_order mo2=std::memory_order_relaxed)
248  volatile noexcept
249  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
250 
251 T* compare_exchange_weak(T& v1, T* v2,
252  std::memory_order mo1=std::memory_order_relaxed,
253  std::memory_order mo2=std::memory_order_relaxed)
254  noexcept
255  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
256 
257 T* compare_exchange_weak(T& v1, T* v2,
258  std::memory_order mo1=std::memory_order_relaxed,
259  std::memory_order mo2=std::memory_order_relaxed)
260  volatile noexcept
261  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
262 
263 T* exchange(T* v, std::memory_order mo=std::memory_order_relaxed) noexcept
264  {return _m.exchange(v, mo);}
265 
266 T* exchange(T* v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
267  {return _m.exchange(v, mo);}
268 
269  RAtomic() {}
270 
271  RAtomic(T* v) : _m(v) {}
272 
273 private:
274 
275 std::atomic<T*> _m;
276 };
277 
278 template<>
279 class RAtomic<bool>
280 {
281 public:
282 
283 // Store and fetch defined here for immediate expansion
284 //
285 bool operator=(bool v) noexcept
286  {_m.store(v, std::memory_order_relaxed); return v;}
287 
288 bool operator=(bool v) volatile noexcept
289  {_m.store(v, std::memory_order_relaxed); return v;}
290 
291  operator bool() noexcept
292  {return _m.load(std::memory_order_relaxed);}
293 
294  operator bool() volatile noexcept
295  {return _m.load(std::memory_order_relaxed);}
296 
297 // Member functions
298 //
299 bool compare_exchange_strong(bool& v1, bool v2,
300  std::memory_order mo1=std::memory_order_relaxed,
301  std::memory_order mo2=std::memory_order_relaxed)
302  noexcept
303  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
304 
305 bool compare_exchange_strong(bool& v1, bool v2,
306  std::memory_order mo1=std::memory_order_relaxed,
307  std::memory_order mo2=std::memory_order_relaxed)
308  volatile noexcept
309  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
310 
311 bool compare_exchange_weak(bool& v1, bool v2,
312  std::memory_order mo1=std::memory_order_relaxed,
313  std::memory_order mo2=std::memory_order_relaxed)
314  noexcept
315  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
316 
317 bool compare_exchange_weak(bool& v1, bool v2,
318  std::memory_order mo1=std::memory_order_relaxed,
319  std::memory_order mo2=std::memory_order_relaxed)
320  volatile noexcept
321  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
322 
323 bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) noexcept
324  {return _m.exchange(v, mo);}
325 
326 bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
327  {return _m.exchange(v, mo);}
328 
329  RAtomic() {}
330 
331  RAtomic(bool v) : _m(v) {}
332 
333 private:
334 
335 std::atomic<bool> _m;
336 };
337 }
338 
339 // Common types
340 //
362 #endif
XrdSys::RAtomic< unsigned char > RAtomic_uchar
XrdSys::RAtomic< uint64_t > RAtomic_uint64_t
XrdSys::RAtomic< short > RAtomic_short
XrdSys::RAtomic< bool > RAtomic_bool
XrdSys::RAtomic< char > RAtomic_char
XrdSys::RAtomic< wchar_t > RAtomic_wchar_t
XrdSys::RAtomic< long long > RAtomic_llong
XrdSys::RAtomic< uint32_t > RAtomic_uint32_t
XrdSys::RAtomic< int16_t > RAtomic_int16_t
XrdSys::RAtomic< uint8_t > RAtomic_uint8_t
XrdSys::RAtomic< int32_t > RAtomic_int32_t
XrdSys::RAtomic< uint16_t > RAtomic_uint16_t
XrdSys::RAtomic< long > RAtomic_long
XrdSys::RAtomic< unsigned long long > RAtomic_ullong
XrdSys::RAtomic< unsigned short > RAtomic_ushort
XrdSys::RAtomic< int64_t > RAtomic_int64_t
XrdSys::RAtomic< unsigned int > RAtomic_uint
XrdSys::RAtomic< unsigned long > RAtomic_ulong
XrdSys::RAtomic< signed char > RAtomic_schar
XrdSys::RAtomic< int > RAtomic_int
XrdSys::RAtomic< int8_t > RAtomic_int8_t
T * compare_exchange_weak(T &v1, T *v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
T * operator--(int) noexcept
T * operator++(int) noexcept
T * exchange(T *v, std::memory_order mo=std::memory_order_relaxed) noexcept
T * operator++(int) volatile noexcept
T * operator++() volatile noexcept
T * operator--() volatile noexcept
T * operator--() noexcept
T * operator-=(ptrdiff_t v) noexcept
T * operator=(T *v) volatile noexcept
T * operator--(int) volatile noexcept
T * compare_exchange_strong(T &v1, T *v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
T * operator=(T *v) noexcept
T * operator+=(ptrdiff_t v) noexcept
T * compare_exchange_strong(T &v1, T *v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
T * operator++() noexcept
T * operator->() noexcept
T * operator-=(ptrdiff_t v) volatile noexcept
T * exchange(T *v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
T * compare_exchange_weak(T &v1, T *v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
T * operator+=(ptrdiff_t v) volatile noexcept
bool operator=(bool v) noexcept
bool operator=(bool v) volatile noexcept
bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) noexcept
bool compare_exchange_weak(bool &v1, bool v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
bool compare_exchange_strong(bool &v1, bool v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
bool compare_exchange_weak(bool &v1, bool v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
bool compare_exchange_strong(bool &v1, bool v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
T operator++(int) noexcept
T operator^=(T v) noexcept
T operator+=(T v) noexcept
T operator&=(T v) volatile noexcept
T fetch_or(T v) noexcept
T operator=(T v) noexcept
T operator--(int) noexcept
T exchange(T v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
T operator|=(T v) volatile noexcept
T compare_exchange_weak(T &v1, T v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
T fetch_xor(T v) noexcept
T operator=(T v) volatile noexcept
T fetch_and(T v) noexcept
T compare_exchange_weak(T &v1, T v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
T operator--(int) volatile noexcept
T operator&=(T v) noexcept
T operator++() volatile noexcept
RAtomic & operator=(const RAtomic &other) volatile noexcept
T operator--() volatile noexcept
T exchange(T v, std::memory_order mo=std::memory_order_relaxed) noexcept
T compare_exchange_strong(T &v1, T v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) noexcept
T compare_exchange_strong(T &v1, T v2, std::memory_order mo1=std::memory_order_relaxed, std::memory_order mo2=std::memory_order_relaxed) volatile noexcept
T operator--() noexcept
T operator^=(T v) volatile noexcept
T operator|=(T v) noexcept
T operator-=(T v) noexcept
RAtomic & operator=(const RAtomic &other) noexcept
T operator++() noexcept
T operator-=(T v) volatile noexcept
T operator+=(T v) volatile noexcept
T operator++(int) volatile noexcept