libstdc++
atomic_0.h
Go to the documentation of this file.
1 // -*- C++ -*- header.
2 
3 // Copyright (C) 2008, 2009, 2010, 2011
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  * Do not attempt to use it directly. @headername{atomic}
29  */
30 
31 #ifndef _GLIBCXX_ATOMIC_0_H
32 #define _GLIBCXX_ATOMIC_0_H 1
33 
34 #pragma GCC system_header
35 
36 namespace std _GLIBCXX_VISIBILITY(default)
37 {
38 _GLIBCXX_BEGIN_NAMESPACE_VERSION
39 
40 // 0 == __atomic0 == Never lock-free
41 namespace __atomic0
42 {
43  _GLIBCXX_BEGIN_EXTERN_C
44 
45  void
46  atomic_flag_clear_explicit(__atomic_flag_base*, memory_order)
47  _GLIBCXX_NOTHROW;
48 
49  void
50  __atomic_flag_wait_explicit(__atomic_flag_base*, memory_order)
51  _GLIBCXX_NOTHROW;
52 
53  _GLIBCXX_CONST __atomic_flag_base*
54  __atomic_flag_for_address(const volatile void* __z) _GLIBCXX_NOTHROW;
55 
56  _GLIBCXX_END_EXTERN_C
57 
58  // Implementation specific defines.
59 #define _ATOMIC_MEMBER_ _M_i
60 
61  // Implementation specific defines.
62 #define _ATOMIC_LOAD_(__a, __x) \
63  ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type; \
64  __i_type* __p = &_ATOMIC_MEMBER_; \
65  __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
66  __atomic_flag_wait_explicit(__g, __x); \
67  __i_type __r = *__p; \
68  atomic_flag_clear_explicit(__g, __x); \
69  __r; })
70 
71 #define _ATOMIC_STORE_(__a, __n, __x) \
72  ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type; \
73  __i_type* __p = &_ATOMIC_MEMBER_; \
74  __typeof__(__n) __w = (__n); \
75  __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
76  __atomic_flag_wait_explicit(__g, __x); \
77  *__p = __w; \
78  atomic_flag_clear_explicit(__g, __x); \
79  __w; })
80 
81 #define _ATOMIC_MODIFY_(__a, __o, __n, __x) \
82  ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type; \
83  __i_type* __p = &_ATOMIC_MEMBER_; \
84  __typeof__(__n) __w = (__n); \
85  __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
86  __atomic_flag_wait_explicit(__g, __x); \
87  __i_type __r = *__p; \
88  *__p __o __w; \
89  atomic_flag_clear_explicit(__g, __x); \
90  __r; })
91 
92 #define _ATOMIC_CMPEXCHNG_(__a, __e, __n, __x) \
93  ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type; \
94  __i_type* __p = &_ATOMIC_MEMBER_; \
95  __typeof__(__e) __q = (__e); \
96  __typeof__(__n) __w = (__n); \
97  bool __r; \
98  __atomic_flag_base* __g = __atomic_flag_for_address(__p); \
99  __atomic_flag_wait_explicit(__g, __x); \
100  __i_type __t = *__p; \
101  if (*__q == __t) \
102  { \
103  *__p = (__i_type)__w; \
104  __r = true; \
105  } \
106  else { *__q = __t; __r = false; } \
107  atomic_flag_clear_explicit(__g, __x); \
108  __r; })
109 
110 
111  /// atomic_flag
112  struct atomic_flag : public __atomic_flag_base
113  {
114  atomic_flag() = default;
115  ~atomic_flag() = default;
116  atomic_flag(const atomic_flag&) = delete;
117  atomic_flag& operator=(const atomic_flag&) = delete;
118  atomic_flag& operator=(const atomic_flag&) volatile = delete;
119 
120  // Conversion to ATOMIC_FLAG_INIT.
121  atomic_flag(bool __i): __atomic_flag_base({ __i }) { }
122 
123  bool
124  test_and_set(memory_order __m = memory_order_seq_cst);
125 
126  bool
127  test_and_set(memory_order __m = memory_order_seq_cst) volatile;
128 
129  void
130  clear(memory_order __m = memory_order_seq_cst);
131 
132  void
133  clear(memory_order __m = memory_order_seq_cst) volatile;
134  };
135 
136 
137  /// Base class for atomic integrals.
138  //
139  // For each of the integral types, define atomic_[integral type] struct
140  //
141  // atomic_bool bool
142  // atomic_char char
143  // atomic_schar signed char
144  // atomic_uchar unsigned char
145  // atomic_short short
146  // atomic_ushort unsigned short
147  // atomic_int int
148  // atomic_uint unsigned int
149  // atomic_long long
150  // atomic_ulong unsigned long
151  // atomic_llong long long
152  // atomic_ullong unsigned long long
153  // atomic_char16_t char16_t
154  // atomic_char32_t char32_t
155  // atomic_wchar_t wchar_t
156 
157  // Base type.
158  // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or 8 bytes,
159  // since that is what GCC built-in functions for atomic memory access work on.
160  template<typename _ITp>
162  {
163  private:
164  typedef _ITp __int_type;
165 
166  __int_type _M_i;
167 
168  public:
169  __atomic_base() = default;
170  ~__atomic_base() = default;
171  __atomic_base(const __atomic_base&) = delete;
172  __atomic_base& operator=(const __atomic_base&) = delete;
173  __atomic_base& operator=(const __atomic_base&) volatile = delete;
174 
175  // Requires __int_type convertible to _M_base._M_i.
176  constexpr __atomic_base(__int_type __i): _M_i (__i) { }
177 
178  operator __int_type() const
179  { return load(); }
180 
181  operator __int_type() const volatile
182  { return load(); }
183 
184  __int_type
185  operator=(__int_type __i)
186  {
187  store(__i);
188  return __i;
189  }
190 
191  __int_type
192  operator=(__int_type __i) volatile
193  {
194  store(__i);
195  return __i;
196  }
197 
198  __int_type
199  operator++(int)
200  { return fetch_add(1); }
201 
202  __int_type
203  operator++(int) volatile
204  { return fetch_add(1); }
205 
206  __int_type
207  operator--(int)
208  { return fetch_sub(1); }
209 
210  __int_type
211  operator--(int) volatile
212  { return fetch_sub(1); }
213 
214  __int_type
215  operator++()
216  { return fetch_add(1) + 1; }
217 
218  __int_type
219  operator++() volatile
220  { return fetch_add(1) + 1; }
221 
222  __int_type
223  operator--()
224  { return fetch_sub(1) - 1; }
225 
226  __int_type
227  operator--() volatile
228  { return fetch_sub(1) - 1; }
229 
230  __int_type
231  operator+=(__int_type __i)
232  { return fetch_add(__i) + __i; }
233 
234  __int_type
235  operator+=(__int_type __i) volatile
236  { return fetch_add(__i) + __i; }
237 
238  __int_type
239  operator-=(__int_type __i)
240  { return fetch_sub(__i) - __i; }
241 
242  __int_type
243  operator-=(__int_type __i) volatile
244  { return fetch_sub(__i) - __i; }
245 
246  __int_type
247  operator&=(__int_type __i)
248  { return fetch_and(__i) & __i; }
249 
250  __int_type
251  operator&=(__int_type __i) volatile
252  { return fetch_and(__i) & __i; }
253 
254  __int_type
255  operator|=(__int_type __i)
256  { return fetch_or(__i) | __i; }
257 
258  __int_type
259  operator|=(__int_type __i) volatile
260  { return fetch_or(__i) | __i; }
261 
262  __int_type
263  operator^=(__int_type __i)
264  { return fetch_xor(__i) ^ __i; }
265 
266  __int_type
267  operator^=(__int_type __i) volatile
268  { return fetch_xor(__i) ^ __i; }
269 
270  bool
271  is_lock_free() const
272  { return false; }
273 
274  bool
275  is_lock_free() const volatile
276  { return false; }
277 
278  void
279  store(__int_type __i, memory_order __m = memory_order_seq_cst)
280  {
281  __glibcxx_assert(__m != memory_order_acquire);
282  __glibcxx_assert(__m != memory_order_acq_rel);
283  __glibcxx_assert(__m != memory_order_consume);
284  _ATOMIC_STORE_(this, __i, __m);
285  }
286 
287  void
288  store(__int_type __i, memory_order __m = memory_order_seq_cst) volatile
289  {
290  __glibcxx_assert(__m != memory_order_acquire);
291  __glibcxx_assert(__m != memory_order_acq_rel);
292  __glibcxx_assert(__m != memory_order_consume);
293  _ATOMIC_STORE_(this, __i, __m);
294  }
295 
296  __int_type
297  load(memory_order __m = memory_order_seq_cst) const
298  {
299  __glibcxx_assert(__m != memory_order_release);
300  __glibcxx_assert(__m != memory_order_acq_rel);
301  return _ATOMIC_LOAD_(this, __m);
302  }
303 
304  __int_type
305  load(memory_order __m = memory_order_seq_cst) const volatile
306  {
307  __glibcxx_assert(__m != memory_order_release);
308  __glibcxx_assert(__m != memory_order_acq_rel);
309  return _ATOMIC_LOAD_(this, __m);
310  }
311 
312  __int_type
313  exchange(__int_type __i, memory_order __m = memory_order_seq_cst)
314  { return _ATOMIC_MODIFY_(this, =, __i, __m); }
315 
316  __int_type
317  exchange(__int_type __i, memory_order __m = memory_order_seq_cst) volatile
318  { return _ATOMIC_MODIFY_(this, =, __i, __m); }
319 
320  bool
321  compare_exchange_weak(__int_type& __i1, __int_type __i2,
322  memory_order __m1, memory_order __m2)
323  {
324  __glibcxx_assert(__m2 != memory_order_release);
325  __glibcxx_assert(__m2 != memory_order_acq_rel);
326  __glibcxx_assert(__m2 <= __m1);
327  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
328  }
329 
330  bool
331  compare_exchange_weak(__int_type& __i1, __int_type __i2,
332  memory_order __m1, memory_order __m2) volatile
333  {
334  __glibcxx_assert(__m2 != memory_order_release);
335  __glibcxx_assert(__m2 != memory_order_acq_rel);
336  __glibcxx_assert(__m2 <= __m1);
337  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
338  }
339 
340  bool
341  compare_exchange_weak(__int_type& __i1, __int_type __i2,
342  memory_order __m = memory_order_seq_cst)
343  {
344  return compare_exchange_weak(__i1, __i2, __m,
345  __calculate_memory_order(__m));
346  }
347 
348  bool
349  compare_exchange_weak(__int_type& __i1, __int_type __i2,
350  memory_order __m = memory_order_seq_cst) volatile
351  {
352  return compare_exchange_weak(__i1, __i2, __m,
353  __calculate_memory_order(__m));
354  }
355 
356  bool
357  compare_exchange_strong(__int_type& __i1, __int_type __i2,
358  memory_order __m1, memory_order __m2)
359  {
360  __glibcxx_assert(__m2 != memory_order_release);
361  __glibcxx_assert(__m2 != memory_order_acq_rel);
362  __glibcxx_assert(__m2 <= __m1);
363  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
364  }
365 
366  bool
367  compare_exchange_strong(__int_type& __i1, __int_type __i2,
368  memory_order __m1, memory_order __m2) volatile
369  {
370  __glibcxx_assert(__m2 != memory_order_release);
371  __glibcxx_assert(__m2 != memory_order_acq_rel);
372  __glibcxx_assert(__m2 <= __m1);
373  return _ATOMIC_CMPEXCHNG_(this, &__i1, __i2, __m1);
374  }
375 
376  bool
377  compare_exchange_strong(__int_type& __i1, __int_type __i2,
378  memory_order __m = memory_order_seq_cst)
379  {
380  return compare_exchange_strong(__i1, __i2, __m,
381  __calculate_memory_order(__m));
382  }
383 
384  bool
385  compare_exchange_strong(__int_type& __i1, __int_type __i2,
386  memory_order __m = memory_order_seq_cst) volatile
387  {
388  return compare_exchange_strong(__i1, __i2, __m,
389  __calculate_memory_order(__m));
390  }
391 
392  __int_type
393  fetch_add(__int_type __i, memory_order __m = memory_order_seq_cst)
394  { return _ATOMIC_MODIFY_(this, +=, __i, __m); }
395 
396  __int_type
397  fetch_add(__int_type __i,
398  memory_order __m = memory_order_seq_cst) volatile
399  { return _ATOMIC_MODIFY_(this, +=, __i, __m); }
400 
401  __int_type
402  fetch_sub(__int_type __i, memory_order __m = memory_order_seq_cst)
403  { return _ATOMIC_MODIFY_(this, -=, __i, __m); }
404 
405  __int_type
406  fetch_sub(__int_type __i,
407  memory_order __m = memory_order_seq_cst) volatile
408  { return _ATOMIC_MODIFY_(this, -=, __i, __m); }
409 
410  __int_type
411  fetch_and(__int_type __i, memory_order __m = memory_order_seq_cst)
412  { return _ATOMIC_MODIFY_(this, &=, __i, __m); }
413 
414  __int_type
415  fetch_and(__int_type __i,
416  memory_order __m = memory_order_seq_cst) volatile
417  { return _ATOMIC_MODIFY_(this, &=, __i, __m); }
418 
419  __int_type
420  fetch_or(__int_type __i, memory_order __m = memory_order_seq_cst)
421  { return _ATOMIC_MODIFY_(this, |=, __i, __m); }
422 
423  __int_type
424  fetch_or(__int_type __i, memory_order __m = memory_order_seq_cst) volatile
425  { return _ATOMIC_MODIFY_(this, |=, __i, __m); }
426 
427  __int_type
428  fetch_xor(__int_type __i, memory_order __m = memory_order_seq_cst)
429  { return _ATOMIC_MODIFY_(this, ^=, __i, __m); }
430 
431  __int_type
432  fetch_xor(__int_type __i,
433  memory_order __m = memory_order_seq_cst) volatile
434  { return _ATOMIC_MODIFY_(this, ^=, __i, __m); }
435  };
436 
437 
438  /// Partial specialization for pointer types.
439  template<typename _PTp>
440  struct __atomic_base<_PTp*>
441  {
442  private:
443  typedef _PTp* __return_pointer_type;
444  typedef void* __pointer_type;
445  __pointer_type _M_i;
446 
447  public:
448  __atomic_base() = default;
449  ~__atomic_base() = default;
450  __atomic_base(const __atomic_base&) = delete;
451  __atomic_base& operator=(const __atomic_base&) = delete;
452  __atomic_base& operator=(const __atomic_base&) volatile = delete;
453 
454  // Requires __pointer_type convertible to _M_i.
455  constexpr __atomic_base(__return_pointer_type __p): _M_i (__p) { }
456 
457  operator __return_pointer_type() const
458  { return reinterpret_cast<__return_pointer_type>(load()); }
459 
460  operator __return_pointer_type() const volatile
461  { return reinterpret_cast<__return_pointer_type>(load()); }
462 
463  __return_pointer_type
464  operator=(__pointer_type __p)
465  {
466  store(__p);
467  return reinterpret_cast<__return_pointer_type>(__p);
468  }
469 
470  __return_pointer_type
471  operator=(__pointer_type __p) volatile
472  {
473  store(__p);
474  return reinterpret_cast<__return_pointer_type>(__p);
475  }
476 
477  __return_pointer_type
478  operator++(int)
479  { return reinterpret_cast<__return_pointer_type>(fetch_add(1)); }
480 
481  __return_pointer_type
482  operator++(int) volatile
483  { return reinterpret_cast<__return_pointer_type>(fetch_add(1)); }
484 
485  __return_pointer_type
486  operator--(int)
487  { return reinterpret_cast<__return_pointer_type>(fetch_sub(1)); }
488 
489  __return_pointer_type
490  operator--(int) volatile
491  { return reinterpret_cast<__return_pointer_type>(fetch_sub(1)); }
492 
493  __return_pointer_type
494  operator++()
495  { return reinterpret_cast<__return_pointer_type>(fetch_add(1) + 1); }
496 
497  __return_pointer_type
498  operator++() volatile
499  { return reinterpret_cast<__return_pointer_type>(fetch_add(1) + 1); }
500 
501  __return_pointer_type
502  operator--()
503  { return reinterpret_cast<__return_pointer_type>(fetch_sub(1) - 1); }
504 
505  __return_pointer_type
506  operator--() volatile
507  { return reinterpret_cast<__return_pointer_type>(fetch_sub(1) - 1); }
508 
509  __return_pointer_type
510  operator+=(ptrdiff_t __d)
511  { return reinterpret_cast<__return_pointer_type>(fetch_add(__d) + __d); }
512 
513  __return_pointer_type
514  operator+=(ptrdiff_t __d) volatile
515  { return reinterpret_cast<__return_pointer_type>(fetch_add(__d) + __d); }
516 
517  __return_pointer_type
518  operator-=(ptrdiff_t __d)
519  { return reinterpret_cast<__return_pointer_type>(fetch_sub(__d) - __d); }
520 
521  __return_pointer_type
522  operator-=(ptrdiff_t __d) volatile
523  { return reinterpret_cast<__return_pointer_type>(fetch_sub(__d) - __d); }
524 
525  bool
526  is_lock_free() const
527  { return true; }
528 
529  bool
530  is_lock_free() const volatile
531  { return true; }
532 
533  void
534  store(__pointer_type __p, memory_order __m = memory_order_seq_cst)
535  {
536  __glibcxx_assert(__m != memory_order_acquire);
537  __glibcxx_assert(__m != memory_order_acq_rel);
538  __glibcxx_assert(__m != memory_order_consume);
539  _ATOMIC_STORE_(this, __p, __m);
540  }
541 
542  void
543  store(__pointer_type __p,
544  memory_order __m = memory_order_seq_cst) volatile
545  {
546  __glibcxx_assert(__m != memory_order_acquire);
547  __glibcxx_assert(__m != memory_order_acq_rel);
548  __glibcxx_assert(__m != memory_order_consume);
549  volatile __pointer_type* __p2 = &_M_i;
550  __typeof__(__p) __w = (__p);
551  __atomic_flag_base* __g = __atomic_flag_for_address(__p2);
552  __atomic_flag_wait_explicit(__g, __m);
553  *__p2 = reinterpret_cast<__pointer_type>(__w);
554  atomic_flag_clear_explicit(__g, __m);
555  __w;
556  }
557 
558  __return_pointer_type
559  load(memory_order __m = memory_order_seq_cst) const
560  {
561  __glibcxx_assert(__m != memory_order_release);
562  __glibcxx_assert(__m != memory_order_acq_rel);
563  void* __v = _ATOMIC_LOAD_(this, __m);
564  return reinterpret_cast<__return_pointer_type>(__v);
565  }
566 
567  __return_pointer_type
568  load(memory_order __m = memory_order_seq_cst) const volatile
569  {
570  __glibcxx_assert(__m != memory_order_release);
571  __glibcxx_assert(__m != memory_order_acq_rel);
572  void* __v = _ATOMIC_LOAD_(this, __m);
573  return reinterpret_cast<__return_pointer_type>(__v);
574  }
575 
576  __return_pointer_type
577  exchange(__pointer_type __p, memory_order __m = memory_order_seq_cst)
578  {
579  void* __v = _ATOMIC_MODIFY_(this, =, __p, __m);
580  return reinterpret_cast<__return_pointer_type>(__v);
581  }
582 
583  __return_pointer_type
584  exchange(__pointer_type __p,
585  memory_order __m = memory_order_seq_cst) volatile
586  {
587  volatile __pointer_type* __p2 = &_M_i;
588  __typeof__(__p) __w = (__p);
589  __atomic_flag_base* __g = __atomic_flag_for_address(__p2);
590  __atomic_flag_wait_explicit(__g, __m);
591  __pointer_type __r = *__p2;
592  *__p2 = __w;
593  atomic_flag_clear_explicit(__g, __m);
594  __r;
595  return reinterpret_cast<__return_pointer_type>(_M_i);
596  }
597 
598  bool
599  compare_exchange_strong(__return_pointer_type& __rp1, __pointer_type __p2,
600  memory_order __m1, memory_order __m2)
601  {
602  __glibcxx_assert(__m2 != memory_order_release);
603  __glibcxx_assert(__m2 != memory_order_acq_rel);
604  __glibcxx_assert(__m2 <= __m1);
605  __pointer_type& __p1 = reinterpret_cast<void*&>(__rp1);
606  return _ATOMIC_CMPEXCHNG_(this, &__p1, __p2, __m1);
607  }
608 
609  bool
610  compare_exchange_strong(__return_pointer_type& __rp1, __pointer_type __p2,
611  memory_order __m1, memory_order __m2) volatile
612  {
613  __glibcxx_assert(__m2 != memory_order_release);
614  __glibcxx_assert(__m2 != memory_order_acq_rel);
615  __glibcxx_assert(__m2 <= __m1);
616  __pointer_type& __p1 = reinterpret_cast<void*&>(__rp1);
617  return _ATOMIC_CMPEXCHNG_(this, &__p1, __p2, __m1);
618  }
619 
620  __return_pointer_type
621  fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst)
622  {
623  void* __v = _ATOMIC_MODIFY_(this, +=, __d, __m);
624  return reinterpret_cast<__return_pointer_type>(__v);
625  }
626 
627  __return_pointer_type
628  fetch_add(ptrdiff_t __d,
629  memory_order __m = memory_order_seq_cst) volatile
630  {
631  void* __v = _ATOMIC_MODIFY_(this, +=, __d, __m);
632  return reinterpret_cast<__return_pointer_type>(__v);
633  }
634 
635  __return_pointer_type
636  fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst)
637  {
638  void* __v = _ATOMIC_MODIFY_(this, -=, __d, __m);
639  return reinterpret_cast<__return_pointer_type>(__v);
640  }
641 
642  __return_pointer_type
643  fetch_sub(ptrdiff_t __d,
644  memory_order __m = memory_order_seq_cst) volatile
645  {
646  void* __v = _ATOMIC_MODIFY_(this, -=, __d, __m);
647  return reinterpret_cast<__return_pointer_type>(__v);
648  }
649  };
650 
651 #undef _ATOMIC_LOAD_
652 #undef _ATOMIC_STORE_
653 #undef _ATOMIC_MODIFY_
654 #undef _ATOMIC_CMPEXCHNG_
655 } // namespace __atomic0
656 
657 _GLIBCXX_END_NAMESPACE_VERSION
658 } // namespace std
659 
660 #endif