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() volatile noexcept
41  {return _m.load(std::memory_order_relaxed);}
42 
43 // Post-increment/decrement (i.e. x++)
44 //
45 T operator++(int) noexcept
46  {return _m.fetch_add(1, std::memory_order_relaxed);}
47 
48 T operator++(int) volatile noexcept
49  {return _m.fetch_add(1, std::memory_order_relaxed);}
50 
51 T operator--(int) noexcept
52  {return _m.fetch_sub(1, std::memory_order_relaxed);}
53 
54 T operator--(int) volatile noexcept
55  {return _m.fetch_sub(1, std::memory_order_relaxed);}
56 
57 // Pre-increment/decrement (i.e.++x)
58 //
59 T operator++() noexcept
60  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
61 
62 T operator++() volatile noexcept
63  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
64 
65 T operator--() noexcept
66  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
67 
68 T operator--() volatile noexcept
69  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
70 
71 T operator+=(T v) noexcept
72  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
73 
74 T operator+=(T v) volatile noexcept
75  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
76 
77 T operator-=(T v) noexcept
78  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
79 
80 T operator-=(T v) volatile noexcept
81  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
82 
83 T operator&=(T v) noexcept
84  {return _m.fetch_and(v, std::memory_order_relaxed) & v;}
85 
86 T operator&=(T v) volatile noexcept
87  {return _m.fetch_and(v, std::memory_order_relaxed) & v;}
88 
89 T operator|=(T v) noexcept
90  {return _m.fetch_or (v, std::memory_order_relaxed) | v;}
91 
92 T operator|=(T v) volatile noexcept
93  {return _m.fetch_or (v, std::memory_order_relaxed) | v;}
94 
95 T operator^=(T v) noexcept
96  {return _m.fetch_xor(v, std::memory_order_relaxed) ^ v;}
97 
98 T operator^=(T v) volatile noexcept
99  {return _m.fetch_xor(v, std::memory_order_relaxed) ^ v;}
100 
101 // Specialty functions that fetch and do a post operation
102 //
103 T fetch_and(T v) noexcept
104  {return _m.fetch_and(v, std::memory_order_relaxed);}
105 
106 T fetch_or(T v) noexcept
107  {return _m.fetch_or (v, std::memory_order_relaxed);}
108 
109 T fetch_xor(T v) noexcept
110  {return _m.fetch_xor(v, std::memory_order_relaxed);}
111 
112 // Member functions
113 //
115  std::memory_order mo1=std::memory_order_relaxed,
116  std::memory_order mo2=std::memory_order_relaxed)
117  noexcept
118  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
119 
121  std::memory_order mo1=std::memory_order_relaxed,
122  std::memory_order mo2=std::memory_order_relaxed)
123  volatile noexcept
124  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
125 
126 T compare_exchange_weak(T& v1, T v2,
127  std::memory_order mo1=std::memory_order_relaxed,
128  std::memory_order mo2=std::memory_order_relaxed)
129  noexcept
130  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
131 
132 T compare_exchange_weak(T& v1, T v2,
133  std::memory_order mo1=std::memory_order_relaxed,
134  std::memory_order mo2=std::memory_order_relaxed)
135  volatile noexcept
136  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
137 
138 T exchange(T v, std::memory_order mo=std::memory_order_relaxed) noexcept
139  {return _m.exchange(v, mo);}
140 
141 T exchange(T v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
142  {return _m.exchange(v, mo);}
143 
144 T load() {return _m.load(std::memory_order_relaxed);}
145 
146  RAtomic() {}
147 
148  RAtomic(T v) : _m(v) {}
149 
150 private:
151 
152 std::atomic<T> _m;
153 };
154 
155 template<typename T>
156 class RAtomic<T*>
157 {
158 public:
159 
160 // Store and fetch defined here for immediate expansion
161 //
162 T* operator=(T* v) noexcept
163  {_m.store(v, std::memory_order_relaxed); return v;}
164 
165 T* operator=(T* v) volatile noexcept
166  {_m.store(v, std::memory_order_relaxed); return v;}
167 
168  operator T*() noexcept
169  {return _m.load(std::memory_order_relaxed);}
170 
171  operator T*() volatile noexcept
172  {return _m.load(std::memory_order_relaxed);}
173 
174  T* operator->() noexcept
175  {return _m.load(std::memory_order_relaxed);}
176 
177 // Post-increment/decrement (i.e. x++)
178 //
179 T* operator++(int) noexcept
180  {return _m.fetch_add(1, std::memory_order_relaxed);}
181 
182 T* operator++(int) volatile noexcept
183  {return _m.fetch_add(1, std::memory_order_relaxed);}
184 
185 T* operator--(int) noexcept
186  {return _m.fetch_sub(1, std::memory_order_relaxed);}
187 
188 T* operator--(int) volatile noexcept
189  {return _m.fetch_sub(1, std::memory_order_relaxed);}
190 
191 // Pre-increment/decrement (i.e.++x)
192 //
193 T* operator++() noexcept
194  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
195 
196 T* operator++() volatile noexcept
197  {return _m.fetch_add(1, std::memory_order_relaxed)+1;}
198 
199 T* operator--() noexcept
200  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
201 
202 T* operator--() volatile noexcept
203  {return _m.fetch_sub(1, std::memory_order_relaxed)-1;}
204 
205 T* operator+=(ptrdiff_t v) noexcept
206  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
207 
208 T* operator+=(ptrdiff_t v) volatile noexcept
209  {return _m.fetch_add(v, std::memory_order_relaxed)+v;}
210 
211 T* operator-=(ptrdiff_t v) noexcept
212  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
213 
214 T* operator-=(ptrdiff_t v) volatile noexcept
215  {return _m.fetch_sub(v, std::memory_order_relaxed)-v;}
216 
217 // Member functions
218 //
219 T* compare_exchange_strong(T& v1, T* v2,
220  std::memory_order mo1=std::memory_order_relaxed,
221  std::memory_order mo2=std::memory_order_relaxed)
222  noexcept
223  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
224 
225 T* compare_exchange_strong(T& v1, T* v2,
226  std::memory_order mo1=std::memory_order_relaxed,
227  std::memory_order mo2=std::memory_order_relaxed)
228  volatile noexcept
229  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
230 
231 T* compare_exchange_weak(T& v1, T* v2,
232  std::memory_order mo1=std::memory_order_relaxed,
233  std::memory_order mo2=std::memory_order_relaxed)
234  noexcept
235  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
236 
237 T* compare_exchange_weak(T& v1, T* v2,
238  std::memory_order mo1=std::memory_order_relaxed,
239  std::memory_order mo2=std::memory_order_relaxed)
240  volatile noexcept
241  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
242 
243 T* exchange(T* v, std::memory_order mo=std::memory_order_relaxed) noexcept
244  {return _m.exchange(v, mo);}
245 
246 T* exchange(T* v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
247  {return _m.exchange(v, mo);}
248 
249  RAtomic() {}
250 
251  RAtomic(T* v) : _m(v) {}
252 
253 private:
254 
255 std::atomic<T*> _m;
256 };
257 
258 template<>
259 class RAtomic<bool>
260 {
261 public:
262 
263 // Store and fetch defined here for immediate expansion
264 //
265 bool operator=(bool v) noexcept
266  {_m.store(v, std::memory_order_relaxed); return v;}
267 
268 bool operator=(bool v) volatile noexcept
269  {_m.store(v, std::memory_order_relaxed); return v;}
270 
271  operator bool() noexcept
272  {return _m.load(std::memory_order_relaxed);}
273 
274  operator bool() volatile noexcept
275  {return _m.load(std::memory_order_relaxed);}
276 
277 // Member functions
278 //
279 bool compare_exchange_strong(bool& v1, bool v2,
280  std::memory_order mo1=std::memory_order_relaxed,
281  std::memory_order mo2=std::memory_order_relaxed)
282  noexcept
283  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
284 
285 bool compare_exchange_strong(bool& v1, bool v2,
286  std::memory_order mo1=std::memory_order_relaxed,
287  std::memory_order mo2=std::memory_order_relaxed)
288  volatile noexcept
289  {return _m.compare_exchange_strong(v1, v2, mo1, mo2);}
290 
291 bool compare_exchange_weak(bool& v1, bool v2,
292  std::memory_order mo1=std::memory_order_relaxed,
293  std::memory_order mo2=std::memory_order_relaxed)
294  noexcept
295  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
296 
297 bool compare_exchange_weak(bool& v1, bool v2,
298  std::memory_order mo1=std::memory_order_relaxed,
299  std::memory_order mo2=std::memory_order_relaxed)
300  volatile noexcept
301  {return _m.compare_exchange_weak(v1, v2, mo1, mo2);}
302 
303 bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) noexcept
304  {return _m.exchange(v, mo);}
305 
306 bool exchange(bool v, std::memory_order mo=std::memory_order_relaxed) volatile noexcept
307  {return _m.exchange(v, mo);}
308 
309 bool load() {return _m.load(std::memory_order_relaxed);}
310 
311  RAtomic() {}
312 
313  RAtomic(bool v) : _m(v) {}
314 
315 private:
316 
317 std::atomic<bool> _m;
318 };
319 }
320 
321 // Common types
322 //
344 #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
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
T operator++() noexcept
T operator-=(T v) volatile noexcept
T operator+=(T v) volatile noexcept
T operator++(int) volatile noexcept