libstdc++
atomic_0.h
Go to the documentation of this file.
1 // -*- C++ -*- header.
2 
3 // Copyright (C) 2008, 2009
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20 
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25 
26 /** @file bits/atomic_0.h
27  * This is an internal header file, included by other library headers.
28  * You should not attempt to use it directly.
29  */
30 
31 #ifndef _GLIBCXX_ATOMIC_0_H
32 #define _GLIBCXX_ATOMIC_0_H 1
33 
34 #pragma GCC system_header
35 
36 // _GLIBCXX_BEGIN_NAMESPACE(std)
37 
38  // 0 == __atomic0 == Never lock-free
39 namespace __atomic0
40 {
41  struct atomic_flag;
42 
43  // Implementation specific defines.
44 #define _ATOMIC_LOAD_(__a, __x) \
45  ({ volatile __typeof__ _ATOMIC_MEMBER_* __p = &_ATOMIC_MEMBER_; \
46  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
47  __atomic_flag_wait_explicit(__g, __x); \
48  __typeof__ _ATOMIC_MEMBER_ __r = *__p; \
49  atomic_flag_clear_explicit(__g, __x); \
50  __r; })
51 
52 #define _ATOMIC_STORE_(__a, __m, __x) \
53  ({ volatile __typeof__ _ATOMIC_MEMBER_* __p = &_ATOMIC_MEMBER_; \
54  __typeof__(__m) __v = (__m); \
55  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
56  __atomic_flag_wait_explicit(__g, __x); \
57  *__p = __v; \
58  atomic_flag_clear_explicit(__g, __x); \
59  __v; })
60 
61 #define _ATOMIC_MODIFY_(__a, __o, __m, __x) \
62  ({ volatile __typeof__ _ATOMIC_MEMBER_* __p = &_ATOMIC_MEMBER_; \
63  __typeof__(__m) __v = (__m); \
64  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
65  __atomic_flag_wait_explicit(__g, __x); \
66  __typeof__ _ATOMIC_MEMBER_ __r = *__p; \
67  *__p __o __v; \
68  atomic_flag_clear_explicit(__g, __x); \
69  __r; })
70 
71 #define _ATOMIC_CMPEXCHNG_(__a, __e, __m, __x) \
72  ({ volatile __typeof__ _ATOMIC_MEMBER_* __p = &_ATOMIC_MEMBER_; \
73  __typeof__(__e) __q = (__e); \
74  __typeof__(__m) __v = (__m); \
75  bool __r; \
76  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
77  __atomic_flag_wait_explicit(__g, __x); \
78  __typeof__ _ATOMIC_MEMBER_ __t__ = *__p; \
79  if (__t__ == *__q) { *__p = __v; __r = true; } \
80  else { *__q = __t__; __r = false; } \
81  atomic_flag_clear_explicit(__g, __x); \
82  __r; })
83 
84  /// atomic_flag
85  struct atomic_flag : public __atomic_flag_base
86  {
87  atomic_flag() = default;
88  ~atomic_flag() = default;
89  atomic_flag(const atomic_flag&) = delete;
90  atomic_flag& operator=(const atomic_flag&) = delete;
91 
92  // Conversion to ATOMIC_FLAG_INIT.
93  atomic_flag(bool __i): __atomic_flag_base({ __i }) { }
94 
95  bool
96  test_and_set(memory_order __m = memory_order_seq_cst) volatile;
97 
98  void
99  clear(memory_order __m = memory_order_seq_cst) volatile;
100  };
101 
102  /// 29.4.2, address types
104  {
105  private:
106  void* _M_i;
107 
108  public:
109  atomic_address() = default;
110  ~atomic_address() = default;
111  atomic_address(const atomic_address&) = delete;
112  atomic_address& operator=(const atomic_address&) = delete;
113 
114  atomic_address(void* __v) { _M_i = __v; }
115 
116  bool
117  is_lock_free() const volatile
118  { return false; }
119 
120  void
121  store(void* __v, memory_order __m = memory_order_seq_cst) volatile
122  {
123  __glibcxx_assert(__m != memory_order_acquire);
124  __glibcxx_assert(__m != memory_order_acq_rel);
125  __glibcxx_assert(__m != memory_order_consume);
126  _ATOMIC_STORE_(this, __v, __m);
127  }
128 
129  void*
130  load(memory_order __m = memory_order_seq_cst) const volatile
131  {
132  __glibcxx_assert(__m != memory_order_release);
133  __glibcxx_assert(__m != memory_order_acq_rel);
134  return _ATOMIC_LOAD_(this, __m);
135  }
136 
137  void*
138  exchange(void* __v, memory_order __m = memory_order_seq_cst) volatile
139  { return _ATOMIC_MODIFY_(this, =, __v, __m); }
140 
141  bool
142  compare_exchange_weak(void*& __v1, void* __v2, memory_order __m1,
143  memory_order __m2) volatile
144  {
145  __glibcxx_assert(__m2 != memory_order_release);
146  __glibcxx_assert(__m2 != memory_order_acq_rel);
147  __glibcxx_assert(__m2 <= __m1);
148  return _ATOMIC_CMPEXCHNG_(this, &__v1, __v2, __m1);
149  }
150 
151  bool
152  compare_exchange_weak(void*& __v1, void* __v2,
153  memory_order __m = memory_order_seq_cst) volatile
154  {
155  return compare_exchange_weak(__v1, __v2, __m,
156  __calculate_memory_order(__m));
157  }
158 
159  bool
160  compare_exchange_strong(void*& __v1, void* __v2, memory_order __m1,
161  memory_order __m2) volatile
162  {
163  __glibcxx_assert(__m2 != memory_order_release);
164  __glibcxx_assert(__m2 != memory_order_acq_rel);
165  __glibcxx_assert(__m2 <= __m1);
166  return _ATOMIC_CMPEXCHNG_(this, &__v1, __v2, __m1);
167  }
168 
169  bool
170  compare_exchange_strong(void*& __v1, void* __v2,
171  memory_order __m = memory_order_seq_cst) volatile
172  {
173  return compare_exchange_strong(__v1, __v2, __m,
174  __calculate_memory_order(__m));
175  }
176 
177  void*
178  fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile
179  {
180  void* volatile* __p = &(_M_i);
181  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p);
182  __atomic_flag_wait_explicit(__g, __m);
183  void* __r = *__p;
184  *__p = (void*)((char*)(*__p) + __d);
185  atomic_flag_clear_explicit(__g, __m);
186  return __r;
187  }
188 
189  void*
190  fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile
191  {
192  void* volatile* __p = &(_M_i);
193  volatile __atomic_flag_base* __g = __atomic_flag_for_address(__p);
194  __atomic_flag_wait_explicit(__g, __m);
195  void* __r = *__p;
196  *__p = (void*)((char*)(*__p) - __d);
197  atomic_flag_clear_explicit(__g, __m);
198  return __r;
199  }
200 
201  operator void*() const volatile
202  { return load(); }
203 
204  void*
205  operator=(void* __v) // XXX volatile
206  {
207  store(__v);
208  return __v;
209  }
210 
211  void*
212  operator+=(ptrdiff_t __d) volatile
213  { return fetch_add(__d) + __d; }
214 
215  void*
216  operator-=(ptrdiff_t __d) volatile
217  { return fetch_sub(__d) - __d; }
218  };
219 
220 
221  // 29.3.1 atomic integral types
222  // For each of the integral types, define atomic_[integral type] struct
223  //
224  // atomic_bool bool
225  // atomic_char char
226  // atomic_schar signed char
227  // atomic_uchar unsigned char
228  // atomic_short short
229  // atomic_ushort unsigned short
230  // atomic_int int
231  // atomic_uint unsigned int
232  // atomic_long long
233  // atomic_ulong unsigned long
234  // atomic_llong long long
235  // atomic_ullong unsigned long long
236  // atomic_char16_t char16_t
237  // atomic_char32_t char32_t
238  // atomic_wchar_t wchar_t
239 
240  // Base type.
241  // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or 8 bytes,
242  // since that is what GCC built-in functions for atomic memory access work on.
243  template<typename _ITp>
244  struct __atomic_base
245  {
246  private:
247  typedef _ITp __integral_type;
248 
249  __integral_type _M_i;
250 
251  public:
252  __atomic_base() = default;
253  ~__atomic_base() = default;
254  __atomic_base(const __atomic_base&) = delete;
255  __atomic_base& operator=(const __atomic_base&) = delete;
256 
257  // Requires __integral_type convertible to _M_base._M_i.
258  __atomic_base(__integral_type __i) { _M_i = __i; }
259 
260  operator __integral_type() const volatile
261  { return load(); }
262 
263  __integral_type
264  operator=(__integral_type __i) // XXX volatile
265  {
266  store(__i);
267  return __i;
268  }
269 
270  __integral_type
271  operator++(int) volatile
272  { return fetch_add(1); }
273 
274  __integral_type
275  operator--(int) volatile
276  { return fetch_sub(1); }
277 
278  __integral_type
279  operator++() volatile
280  { return fetch_add(1) + 1; }
281 
282  __integral_type
283  operator--() volatile
284  { return fetch_sub(1) - 1; }
285 
286  __integral_type
287  operator+=(__integral_type __i) volatile
288  { return fetch_add(__i) + __i; }
289 
290  __integral_type
291  operator-=(__integral_type __i) volatile
292  { return fetch_sub(__i) - __i; }
293 
294  __integral_type
295  operator&=(__integral_type __i) volatile
296  { return fetch_and(__i) & __i; }
297 
298  __integral_type
299  operator|=(__integral_type __i) volatile
300  { return fetch_or(__i) | __i; }
301 
302  __integral_type
303  operator^=(__integral_type __i) volatile
304  { return fetch_xor(__i) ^ __i; }
305 
306  bool
307  is_lock_free() const volatile
308  { return false; }
309 
310  void
311  store(__integral_type __i,
312  memory_order __m = memory_order_seq_cst) volatile
313  {
314  __glibcxx_assert(__m != memory_order_acquire);
315  __glibcxx_assert(__m != memory_order_acq_rel);
316  __glibcxx_assert(__m != memory_order_consume);
317  _ATOMIC_STORE_(this, __i, __m);
318  }
319 
320  __integral_type
321  load(memory_order __m = memory_order_seq_cst) const volatile
322  {
323  __glibcxx_assert(__m != memory_order_release);
324  __glibcxx_assert(__m != memory_order_acq_rel);
325  return _ATOMIC_LOAD_(this, __m);
326  }
327 
328  __integral_type
329  exchange(__integral_type __i,
330  memory_order __m = memory_order_seq_cst) volatile
331  { return _ATOMIC_MODIFY_(this, =, __i, __m); }
332 
333  bool
334  compare_exchange_weak(__integral_type& __i1, __integral_type __i2,
335  memory_order __m1, memory_order __m2) volatile
336  {
337  __glibcxx_assert(__m2 != memory_order_release);
338  __glibcxx_assert(__m2 != memory_order_acq_rel);
339  __glibcxx_assert(__m2 <= __m1);
340  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
341  }
342 
343  bool
344  compare_exchange_weak(__integral_type& __i1, __integral_type __i2,
345  memory_order __m = memory_order_seq_cst) volatile
346  {
347  return compare_exchange_weak(__i1, __i2, __m,
348  __calculate_memory_order(__m));
349  }
350 
351  bool
352  compare_exchange_strong(__integral_type& __i1, __integral_type __i2,
353  memory_order __m1, memory_order __m2) volatile
354  {
355  __glibcxx_assert(__m2 != memory_order_release);
356  __glibcxx_assert(__m2 != memory_order_acq_rel);
357  __glibcxx_assert(__m2 <= __m1);
358  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
359  }
360 
361  bool
362  compare_exchange_strong(__integral_type& __i1, __integral_type __i2,
363  memory_order __m = memory_order_seq_cst) volatile
364  {
365  return compare_exchange_strong(__i1, __i2, __m,
366  __calculate_memory_order(__m));
367  }
368 
369  __integral_type
370  fetch_add(__integral_type __i,
371  memory_order __m = memory_order_seq_cst) volatile
372  { return _ATOMIC_MODIFY_(this, +=, __i, __m); }
373 
374  __integral_type
375  fetch_sub(__integral_type __i,
376  memory_order __m = memory_order_seq_cst) volatile
377  { return _ATOMIC_MODIFY_(this, -=, __i, __m); }
378 
379  __integral_type
380  fetch_and(__integral_type __i,
381  memory_order __m = memory_order_seq_cst) volatile
382  { return _ATOMIC_MODIFY_(this, &=, __i, __m); }
383 
384  __integral_type
385  fetch_or(__integral_type __i,
386  memory_order __m = memory_order_seq_cst) volatile
387  { return _ATOMIC_MODIFY_(this, |=, __i, __m); }
388 
389  __integral_type
390  fetch_xor(__integral_type __i,
391  memory_order __m = memory_order_seq_cst) volatile
392  { return _ATOMIC_MODIFY_(this, ^=, __i, __m); }
393  };
394 
395 
396  /// atomic_bool
397  // NB: No operators or fetch-operations for this type.
398  struct atomic_bool
399  {
400  private:
401  __atomic_base<bool> _M_base;
402 
403  public:
404  atomic_bool() = default;
405  ~atomic_bool() = default;
406  atomic_bool(const atomic_bool&) = delete;
407  atomic_bool& operator=(const atomic_bool&) = delete;
408 
409  atomic_bool(bool __i) : _M_base(__i) { }
410 
411  bool
412  operator=(bool __i) // XXX volatile
413  { return _M_base.operator=(__i); }
414 
415  operator bool() const volatile
416  { return _M_base.load(); }
417 
418  bool
419  is_lock_free() const volatile
420  { return _M_base.is_lock_free(); }
421 
422  void
423  store(bool __i, memory_order __m = memory_order_seq_cst) volatile
424  { _M_base.store(__i, __m); }
425 
426  bool
427  load(memory_order __m = memory_order_seq_cst) const volatile
428  { return _M_base.load(__m); }
429 
430  bool
431  exchange(bool __i, memory_order __m = memory_order_seq_cst) volatile
432  { return _M_base.exchange(__i, __m); }
433 
434  bool
435  compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
436  memory_order __m2) volatile
437  { return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
438 
439  bool
440  compare_exchange_weak(bool& __i1, bool __i2,
441  memory_order __m = memory_order_seq_cst) volatile
442  { return _M_base.compare_exchange_weak(__i1, __i2, __m); }
443 
444  bool
445  compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
446  memory_order __m2) volatile
447  { return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
448 
449 
450  bool
451  compare_exchange_strong(bool& __i1, bool __i2,
452  memory_order __m = memory_order_seq_cst) volatile
453  { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
454  };
455 
456 #undef _ATOMIC_LOAD_
457 #undef _ATOMIC_STORE_
458 #undef _ATOMIC_MODIFY_
459 #undef _ATOMIC_CMPEXCHNG_
460 } // namespace __atomic0
461 
462 // _GLIBCXX_END_NAMESPACE
463 
464 #endif
atomic_flag
Definition: atomic_0.h:85
29.4.2, address types
Definition: atomic_0.h:103
memory_order
Enumeration for memory_order.
Definition: stdatomic.h:47
atomic_bool
Definition: atomic_0.h:398