Line data Source code
1 : // -*- C++ -*- header.
2 :
3 : // Copyright (C) 2008-2019 Free Software Foundation, Inc.
4 : //
5 : // This file is part of the GNU ISO C++ Library. This library is free
6 : // software; you can redistribute it and/or modify it under the
7 : // terms of the GNU General Public License as published by the
8 : // Free Software Foundation; either version 3, or (at your option)
9 : // any later version.
10 :
11 : // This library is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 :
16 : // Under Section 7 of GPL version 3, you are granted additional
17 : // permissions described in the GCC Runtime Library Exception, version
18 : // 3.1, as published by the Free Software Foundation.
19 :
20 : // You should have received a copy of the GNU General Public License and
21 : // a copy of the GCC Runtime Library Exception along with this program;
22 : // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 : // <http://www.gnu.org/licenses/>.
24 :
25 : /** @file bits/atomic_base.h
26 : * This is an internal header file, included by other library headers.
27 : * Do not attempt to use it directly. @headername{atomic}
28 : */
29 :
30 : #ifndef _GLIBCXX_ATOMIC_BASE_H
31 : #define _GLIBCXX_ATOMIC_BASE_H 1
32 :
33 : #pragma GCC system_header
34 :
35 : #include <bits/c++config.h>
36 : #include <stdint.h>
37 : #include <bits/atomic_lockfree_defines.h>
38 :
39 : #ifndef _GLIBCXX_ALWAYS_INLINE
40 : #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__))
41 : #endif
42 :
43 : namespace std _GLIBCXX_VISIBILITY(default)
44 : {
45 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 :
47 : /**
48 : * @defgroup atomics Atomics
49 : *
50 : * Components for performing atomic operations.
51 : * @{
52 : */
53 :
54 : /// Enumeration for memory_order
55 : #if __cplusplus > 201703L
56 : enum class memory_order : int
57 : {
58 : relaxed,
59 : consume,
60 : acquire,
61 : release,
62 : acq_rel,
63 : seq_cst
64 : };
65 :
66 : inline constexpr memory_order memory_order_relaxed = memory_order::relaxed;
67 : inline constexpr memory_order memory_order_consume = memory_order::consume;
68 : inline constexpr memory_order memory_order_acquire = memory_order::acquire;
69 : inline constexpr memory_order memory_order_release = memory_order::release;
70 : inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel;
71 : inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst;
72 : #else
73 : typedef enum memory_order
74 : {
75 : memory_order_relaxed,
76 : memory_order_consume,
77 : memory_order_acquire,
78 : memory_order_release,
79 : memory_order_acq_rel,
80 : memory_order_seq_cst
81 : } memory_order;
82 : #endif
83 :
84 : enum __memory_order_modifier
85 : {
86 : __memory_order_mask = 0x0ffff,
87 : __memory_order_modifier_mask = 0xffff0000,
88 : __memory_order_hle_acquire = 0x10000,
89 : __memory_order_hle_release = 0x20000
90 : };
91 :
92 : constexpr memory_order
93 : operator|(memory_order __m, __memory_order_modifier __mod)
94 : {
95 : return memory_order(int(__m) | int(__mod));
96 : }
97 :
98 : constexpr memory_order
99 : operator&(memory_order __m, __memory_order_modifier __mod)
100 : {
101 : return memory_order(int(__m) & int(__mod));
102 : }
103 :
104 : // Drop release ordering as per [atomics.types.operations.req]/21
105 : constexpr memory_order
106 : __cmpexch_failure_order2(memory_order __m) noexcept
107 : {
108 : return __m == memory_order_acq_rel ? memory_order_acquire
109 : : __m == memory_order_release ? memory_order_relaxed : __m;
110 : }
111 :
112 : constexpr memory_order
113 : __cmpexch_failure_order(memory_order __m) noexcept
114 : {
115 : return memory_order(__cmpexch_failure_order2(__m & __memory_order_mask)
116 : | __memory_order_modifier(__m & __memory_order_modifier_mask));
117 : }
118 :
119 : _GLIBCXX_ALWAYS_INLINE void
120 : atomic_thread_fence(memory_order __m) noexcept
121 : { __atomic_thread_fence(int(__m)); }
122 :
123 : _GLIBCXX_ALWAYS_INLINE void
124 : atomic_signal_fence(memory_order __m) noexcept
125 : { __atomic_signal_fence(int(__m)); }
126 :
127 : /// kill_dependency
128 : template<typename _Tp>
129 : inline _Tp
130 : kill_dependency(_Tp __y) noexcept
131 : {
132 : _Tp __ret(__y);
133 : return __ret;
134 : }
135 :
136 :
137 : // Base types for atomics.
138 : template<typename _IntTp>
139 : struct __atomic_base;
140 :
141 :
142 : #define ATOMIC_VAR_INIT(_VI) { _VI }
143 :
144 : template<typename _Tp>
145 : struct atomic;
146 :
147 : template<typename _Tp>
148 : struct atomic<_Tp*>;
149 :
150 : /* The target's "set" value for test-and-set may not be exactly 1. */
151 : #if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
152 : typedef bool __atomic_flag_data_type;
153 : #else
154 : typedef unsigned char __atomic_flag_data_type;
155 : #endif
156 :
157 : /**
158 : * @brief Base type for atomic_flag.
159 : *
160 : * Base type is POD with data, allowing atomic_flag to derive from
161 : * it and meet the standard layout type requirement. In addition to
162 : * compatibility with a C interface, this allows different
163 : * implementations of atomic_flag to use the same atomic operation
164 : * functions, via a standard conversion to the __atomic_flag_base
165 : * argument.
166 : */
167 : _GLIBCXX_BEGIN_EXTERN_C
168 :
169 : struct __atomic_flag_base
170 : {
171 : __atomic_flag_data_type _M_i;
172 : };
173 :
174 : _GLIBCXX_END_EXTERN_C
175 :
176 : #define ATOMIC_FLAG_INIT { 0 }
177 :
178 : /// atomic_flag
179 : struct atomic_flag : public __atomic_flag_base
180 : {
181 : atomic_flag() noexcept = default;
182 : ~atomic_flag() noexcept = default;
183 : atomic_flag(const atomic_flag&) = delete;
184 : atomic_flag& operator=(const atomic_flag&) = delete;
185 : atomic_flag& operator=(const atomic_flag&) volatile = delete;
186 :
187 : // Conversion to ATOMIC_FLAG_INIT.
188 : constexpr atomic_flag(bool __i) noexcept
189 : : __atomic_flag_base{ _S_init(__i) }
190 : { }
191 :
192 : _GLIBCXX_ALWAYS_INLINE bool
193 : test_and_set(memory_order __m = memory_order_seq_cst) noexcept
194 : {
195 : return __atomic_test_and_set (&_M_i, int(__m));
196 : }
197 :
198 : _GLIBCXX_ALWAYS_INLINE bool
199 : test_and_set(memory_order __m = memory_order_seq_cst) volatile noexcept
200 : {
201 : return __atomic_test_and_set (&_M_i, int(__m));
202 : }
203 :
204 : _GLIBCXX_ALWAYS_INLINE void
205 : clear(memory_order __m = memory_order_seq_cst) noexcept
206 : {
207 : memory_order __b = __m & __memory_order_mask;
208 : __glibcxx_assert(__b != memory_order_consume);
209 : __glibcxx_assert(__b != memory_order_acquire);
210 : __glibcxx_assert(__b != memory_order_acq_rel);
211 :
212 : __atomic_clear (&_M_i, int(__m));
213 : }
214 :
215 : _GLIBCXX_ALWAYS_INLINE void
216 : clear(memory_order __m = memory_order_seq_cst) volatile noexcept
217 : {
218 : memory_order __b = __m & __memory_order_mask;
219 : __glibcxx_assert(__b != memory_order_consume);
220 : __glibcxx_assert(__b != memory_order_acquire);
221 : __glibcxx_assert(__b != memory_order_acq_rel);
222 :
223 : __atomic_clear (&_M_i, int(__m));
224 : }
225 :
226 : private:
227 : static constexpr __atomic_flag_data_type
228 : _S_init(bool __i)
229 : { return __i ? __GCC_ATOMIC_TEST_AND_SET_TRUEVAL : 0; }
230 : };
231 :
232 :
233 : /// Base class for atomic integrals.
234 : //
235 : // For each of the integral types, define atomic_[integral type] struct
236 : //
237 : // atomic_bool bool
238 : // atomic_char char
239 : // atomic_schar signed char
240 : // atomic_uchar unsigned char
241 : // atomic_short short
242 : // atomic_ushort unsigned short
243 : // atomic_int int
244 : // atomic_uint unsigned int
245 : // atomic_long long
246 : // atomic_ulong unsigned long
247 : // atomic_llong long long
248 : // atomic_ullong unsigned long long
249 : // atomic_char8_t char8_t
250 : // atomic_char16_t char16_t
251 : // atomic_char32_t char32_t
252 : // atomic_wchar_t wchar_t
253 : //
254 : // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or
255 : // 8 bytes, since that is what GCC built-in functions for atomic
256 : // memory access expect.
257 : template<typename _ITp>
258 : struct __atomic_base
259 : {
260 : using value_type = _ITp;
261 : using difference_type = value_type;
262 :
263 : private:
264 : typedef _ITp __int_type;
265 :
266 : static constexpr int _S_alignment =
267 : sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp);
268 :
269 : alignas(_S_alignment) __int_type _M_i;
270 :
271 : public:
272 : __atomic_base() noexcept = default;
273 : ~__atomic_base() noexcept = default;
274 : __atomic_base(const __atomic_base&) = delete;
275 : __atomic_base& operator=(const __atomic_base&) = delete;
276 : __atomic_base& operator=(const __atomic_base&) volatile = delete;
277 :
278 : // Requires __int_type convertible to _M_i.
279 0 : constexpr __atomic_base(__int_type __i) noexcept : _M_i (__i) { }
280 :
281 : operator __int_type() const noexcept
282 : { return load(); }
283 :
284 : operator __int_type() const volatile noexcept
285 : { return load(); }
286 :
287 : __int_type
288 : operator=(__int_type __i) noexcept
289 : {
290 : store(__i);
291 : return __i;
292 : }
293 :
294 : __int_type
295 : operator=(__int_type __i) volatile noexcept
296 : {
297 : store(__i);
298 : return __i;
299 : }
300 :
301 : __int_type
302 : operator++(int) noexcept
303 : { return fetch_add(1); }
304 :
305 : __int_type
306 : operator++(int) volatile noexcept
307 : { return fetch_add(1); }
308 :
309 : __int_type
310 : operator--(int) noexcept
311 : { return fetch_sub(1); }
312 :
313 : __int_type
314 : operator--(int) volatile noexcept
315 : { return fetch_sub(1); }
316 :
317 : __int_type
318 : operator++() noexcept
319 : { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
320 :
321 : __int_type
322 : operator++() volatile noexcept
323 : { return __atomic_add_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
324 :
325 : __int_type
326 : operator--() noexcept
327 : { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
328 :
329 : __int_type
330 : operator--() volatile noexcept
331 : { return __atomic_sub_fetch(&_M_i, 1, int(memory_order_seq_cst)); }
332 :
333 : __int_type
334 : operator+=(__int_type __i) noexcept
335 : { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
336 :
337 : __int_type
338 : operator+=(__int_type __i) volatile noexcept
339 : { return __atomic_add_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
340 :
341 : __int_type
342 : operator-=(__int_type __i) noexcept
343 : { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
344 :
345 : __int_type
346 : operator-=(__int_type __i) volatile noexcept
347 : { return __atomic_sub_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
348 :
349 : __int_type
350 : operator&=(__int_type __i) noexcept
351 : { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
352 :
353 : __int_type
354 : operator&=(__int_type __i) volatile noexcept
355 : { return __atomic_and_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
356 :
357 : __int_type
358 : operator|=(__int_type __i) noexcept
359 : { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
360 :
361 : __int_type
362 : operator|=(__int_type __i) volatile noexcept
363 : { return __atomic_or_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
364 :
365 : __int_type
366 : operator^=(__int_type __i) noexcept
367 : { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
368 :
369 : __int_type
370 : operator^=(__int_type __i) volatile noexcept
371 : { return __atomic_xor_fetch(&_M_i, __i, int(memory_order_seq_cst)); }
372 :
373 : bool
374 : is_lock_free() const noexcept
375 : {
376 : // Use a fake, minimally aligned pointer.
377 : return __atomic_is_lock_free(sizeof(_M_i),
378 : reinterpret_cast<void *>(-_S_alignment));
379 : }
380 :
381 : bool
382 : is_lock_free() const volatile noexcept
383 : {
384 : // Use a fake, minimally aligned pointer.
385 : return __atomic_is_lock_free(sizeof(_M_i),
386 : reinterpret_cast<void *>(-_S_alignment));
387 : }
388 :
389 : _GLIBCXX_ALWAYS_INLINE void
390 : store(__int_type __i, memory_order __m = memory_order_seq_cst) noexcept
391 : {
392 : memory_order __b = __m & __memory_order_mask;
393 : __glibcxx_assert(__b != memory_order_acquire);
394 : __glibcxx_assert(__b != memory_order_acq_rel);
395 : __glibcxx_assert(__b != memory_order_consume);
396 :
397 : __atomic_store_n(&_M_i, __i, int(__m));
398 : }
399 :
400 : _GLIBCXX_ALWAYS_INLINE void
401 : store(__int_type __i,
402 : memory_order __m = memory_order_seq_cst) volatile noexcept
403 : {
404 : memory_order __b = __m & __memory_order_mask;
405 : __glibcxx_assert(__b != memory_order_acquire);
406 : __glibcxx_assert(__b != memory_order_acq_rel);
407 : __glibcxx_assert(__b != memory_order_consume);
408 :
409 : __atomic_store_n(&_M_i, __i, int(__m));
410 : }
411 :
412 : _GLIBCXX_ALWAYS_INLINE __int_type
413 0 : load(memory_order __m = memory_order_seq_cst) const noexcept
414 : {
415 0 : memory_order __b = __m & __memory_order_mask;
416 : __glibcxx_assert(__b != memory_order_release);
417 : __glibcxx_assert(__b != memory_order_acq_rel);
418 :
419 0 : return __atomic_load_n(&_M_i, int(__m));
420 : }
421 :
422 : _GLIBCXX_ALWAYS_INLINE __int_type
423 : load(memory_order __m = memory_order_seq_cst) const volatile noexcept
424 : {
425 : memory_order __b = __m & __memory_order_mask;
426 : __glibcxx_assert(__b != memory_order_release);
427 : __glibcxx_assert(__b != memory_order_acq_rel);
428 :
429 : return __atomic_load_n(&_M_i, int(__m));
430 : }
431 :
432 : _GLIBCXX_ALWAYS_INLINE __int_type
433 : exchange(__int_type __i,
434 : memory_order __m = memory_order_seq_cst) noexcept
435 : {
436 : return __atomic_exchange_n(&_M_i, __i, int(__m));
437 : }
438 :
439 :
440 : _GLIBCXX_ALWAYS_INLINE __int_type
441 : exchange(__int_type __i,
442 : memory_order __m = memory_order_seq_cst) volatile noexcept
443 : {
444 : return __atomic_exchange_n(&_M_i, __i, int(__m));
445 : }
446 :
447 : _GLIBCXX_ALWAYS_INLINE bool
448 0 : compare_exchange_weak(__int_type& __i1, __int_type __i2,
449 : memory_order __m1, memory_order __m2) noexcept
450 : {
451 0 : memory_order __b2 = __m2 & __memory_order_mask;
452 0 : memory_order __b1 = __m1 & __memory_order_mask;
453 : __glibcxx_assert(__b2 != memory_order_release);
454 : __glibcxx_assert(__b2 != memory_order_acq_rel);
455 : __glibcxx_assert(__b2 <= __b1);
456 :
457 0 : return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
458 : int(__m1), int(__m2));
459 : }
460 :
461 : _GLIBCXX_ALWAYS_INLINE bool
462 : compare_exchange_weak(__int_type& __i1, __int_type __i2,
463 : memory_order __m1,
464 : memory_order __m2) volatile noexcept
465 : {
466 : memory_order __b2 = __m2 & __memory_order_mask;
467 : memory_order __b1 = __m1 & __memory_order_mask;
468 : __glibcxx_assert(__b2 != memory_order_release);
469 : __glibcxx_assert(__b2 != memory_order_acq_rel);
470 : __glibcxx_assert(__b2 <= __b1);
471 :
472 : return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
473 : int(__m1), int(__m2));
474 : }
475 :
476 : _GLIBCXX_ALWAYS_INLINE bool
477 : compare_exchange_weak(__int_type& __i1, __int_type __i2,
478 : memory_order __m = memory_order_seq_cst) noexcept
479 : {
480 : return compare_exchange_weak(__i1, __i2, __m,
481 : __cmpexch_failure_order(__m));
482 : }
483 :
484 : _GLIBCXX_ALWAYS_INLINE bool
485 : compare_exchange_weak(__int_type& __i1, __int_type __i2,
486 : memory_order __m = memory_order_seq_cst) volatile noexcept
487 : {
488 : return compare_exchange_weak(__i1, __i2, __m,
489 : __cmpexch_failure_order(__m));
490 : }
491 :
492 : _GLIBCXX_ALWAYS_INLINE bool
493 : compare_exchange_strong(__int_type& __i1, __int_type __i2,
494 : memory_order __m1, memory_order __m2) noexcept
495 : {
496 : memory_order __b2 = __m2 & __memory_order_mask;
497 : memory_order __b1 = __m1 & __memory_order_mask;
498 : __glibcxx_assert(__b2 != memory_order_release);
499 : __glibcxx_assert(__b2 != memory_order_acq_rel);
500 : __glibcxx_assert(__b2 <= __b1);
501 :
502 : return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
503 : int(__m1), int(__m2));
504 : }
505 :
506 : _GLIBCXX_ALWAYS_INLINE bool
507 : compare_exchange_strong(__int_type& __i1, __int_type __i2,
508 : memory_order __m1,
509 : memory_order __m2) volatile noexcept
510 : {
511 : memory_order __b2 = __m2 & __memory_order_mask;
512 : memory_order __b1 = __m1 & __memory_order_mask;
513 :
514 : __glibcxx_assert(__b2 != memory_order_release);
515 : __glibcxx_assert(__b2 != memory_order_acq_rel);
516 : __glibcxx_assert(__b2 <= __b1);
517 :
518 : return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 0,
519 : int(__m1), int(__m2));
520 : }
521 :
522 : _GLIBCXX_ALWAYS_INLINE bool
523 : compare_exchange_strong(__int_type& __i1, __int_type __i2,
524 : memory_order __m = memory_order_seq_cst) noexcept
525 : {
526 : return compare_exchange_strong(__i1, __i2, __m,
527 : __cmpexch_failure_order(__m));
528 : }
529 :
530 : _GLIBCXX_ALWAYS_INLINE bool
531 : compare_exchange_strong(__int_type& __i1, __int_type __i2,
532 : memory_order __m = memory_order_seq_cst) volatile noexcept
533 : {
534 : return compare_exchange_strong(__i1, __i2, __m,
535 : __cmpexch_failure_order(__m));
536 : }
537 :
538 : _GLIBCXX_ALWAYS_INLINE __int_type
539 0 : fetch_add(__int_type __i,
540 : memory_order __m = memory_order_seq_cst) noexcept
541 0 : { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
542 :
543 : _GLIBCXX_ALWAYS_INLINE __int_type
544 : fetch_add(__int_type __i,
545 : memory_order __m = memory_order_seq_cst) volatile noexcept
546 : { return __atomic_fetch_add(&_M_i, __i, int(__m)); }
547 :
548 : _GLIBCXX_ALWAYS_INLINE __int_type
549 0 : fetch_sub(__int_type __i,
550 : memory_order __m = memory_order_seq_cst) noexcept
551 0 : { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
552 :
553 : _GLIBCXX_ALWAYS_INLINE __int_type
554 : fetch_sub(__int_type __i,
555 : memory_order __m = memory_order_seq_cst) volatile noexcept
556 : { return __atomic_fetch_sub(&_M_i, __i, int(__m)); }
557 :
558 : _GLIBCXX_ALWAYS_INLINE __int_type
559 : fetch_and(__int_type __i,
560 : memory_order __m = memory_order_seq_cst) noexcept
561 : { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
562 :
563 : _GLIBCXX_ALWAYS_INLINE __int_type
564 : fetch_and(__int_type __i,
565 : memory_order __m = memory_order_seq_cst) volatile noexcept
566 : { return __atomic_fetch_and(&_M_i, __i, int(__m)); }
567 :
568 : _GLIBCXX_ALWAYS_INLINE __int_type
569 : fetch_or(__int_type __i,
570 : memory_order __m = memory_order_seq_cst) noexcept
571 : { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
572 :
573 : _GLIBCXX_ALWAYS_INLINE __int_type
574 : fetch_or(__int_type __i,
575 : memory_order __m = memory_order_seq_cst) volatile noexcept
576 : { return __atomic_fetch_or(&_M_i, __i, int(__m)); }
577 :
578 : _GLIBCXX_ALWAYS_INLINE __int_type
579 : fetch_xor(__int_type __i,
580 : memory_order __m = memory_order_seq_cst) noexcept
581 : { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
582 :
583 : _GLIBCXX_ALWAYS_INLINE __int_type
584 : fetch_xor(__int_type __i,
585 : memory_order __m = memory_order_seq_cst) volatile noexcept
586 : { return __atomic_fetch_xor(&_M_i, __i, int(__m)); }
587 : };
588 :
589 :
590 : /// Partial specialization for pointer types.
591 : template<typename _PTp>
592 : struct __atomic_base<_PTp*>
593 : {
594 : private:
595 : typedef _PTp* __pointer_type;
596 :
597 : __pointer_type _M_p;
598 :
599 : // Factored out to facilitate explicit specialization.
600 : constexpr ptrdiff_t
601 : _M_type_size(ptrdiff_t __d) const { return __d * sizeof(_PTp); }
602 :
603 : constexpr ptrdiff_t
604 : _M_type_size(ptrdiff_t __d) const volatile { return __d * sizeof(_PTp); }
605 :
606 : public:
607 : __atomic_base() noexcept = default;
608 : ~__atomic_base() noexcept = default;
609 : __atomic_base(const __atomic_base&) = delete;
610 : __atomic_base& operator=(const __atomic_base&) = delete;
611 : __atomic_base& operator=(const __atomic_base&) volatile = delete;
612 :
613 : // Requires __pointer_type convertible to _M_p.
614 : constexpr __atomic_base(__pointer_type __p) noexcept : _M_p (__p) { }
615 :
616 : operator __pointer_type() const noexcept
617 : { return load(); }
618 :
619 : operator __pointer_type() const volatile noexcept
620 : { return load(); }
621 :
622 : __pointer_type
623 : operator=(__pointer_type __p) noexcept
624 : {
625 : store(__p);
626 : return __p;
627 : }
628 :
629 : __pointer_type
630 : operator=(__pointer_type __p) volatile noexcept
631 : {
632 : store(__p);
633 : return __p;
634 : }
635 :
636 : __pointer_type
637 : operator++(int) noexcept
638 : { return fetch_add(1); }
639 :
640 : __pointer_type
641 : operator++(int) volatile noexcept
642 : { return fetch_add(1); }
643 :
644 : __pointer_type
645 : operator--(int) noexcept
646 : { return fetch_sub(1); }
647 :
648 : __pointer_type
649 : operator--(int) volatile noexcept
650 : { return fetch_sub(1); }
651 :
652 : __pointer_type
653 : operator++() noexcept
654 : { return __atomic_add_fetch(&_M_p, _M_type_size(1),
655 : int(memory_order_seq_cst)); }
656 :
657 : __pointer_type
658 : operator++() volatile noexcept
659 : { return __atomic_add_fetch(&_M_p, _M_type_size(1),
660 : int(memory_order_seq_cst)); }
661 :
662 : __pointer_type
663 : operator--() noexcept
664 : { return __atomic_sub_fetch(&_M_p, _M_type_size(1),
665 : int(memory_order_seq_cst)); }
666 :
667 : __pointer_type
668 : operator--() volatile noexcept
669 : { return __atomic_sub_fetch(&_M_p, _M_type_size(1),
670 : int(memory_order_seq_cst)); }
671 :
672 : __pointer_type
673 : operator+=(ptrdiff_t __d) noexcept
674 : { return __atomic_add_fetch(&_M_p, _M_type_size(__d),
675 : int(memory_order_seq_cst)); }
676 :
677 : __pointer_type
678 : operator+=(ptrdiff_t __d) volatile noexcept
679 : { return __atomic_add_fetch(&_M_p, _M_type_size(__d),
680 : int(memory_order_seq_cst)); }
681 :
682 : __pointer_type
683 : operator-=(ptrdiff_t __d) noexcept
684 : { return __atomic_sub_fetch(&_M_p, _M_type_size(__d),
685 : int(memory_order_seq_cst)); }
686 :
687 : __pointer_type
688 : operator-=(ptrdiff_t __d) volatile noexcept
689 : { return __atomic_sub_fetch(&_M_p, _M_type_size(__d),
690 : int(memory_order_seq_cst)); }
691 :
692 : bool
693 : is_lock_free() const noexcept
694 : {
695 : // Produce a fake, minimally aligned pointer.
696 : return __atomic_is_lock_free(sizeof(_M_p),
697 : reinterpret_cast<void *>(-__alignof(_M_p)));
698 : }
699 :
700 : bool
701 : is_lock_free() const volatile noexcept
702 : {
703 : // Produce a fake, minimally aligned pointer.
704 : return __atomic_is_lock_free(sizeof(_M_p),
705 : reinterpret_cast<void *>(-__alignof(_M_p)));
706 : }
707 :
708 : _GLIBCXX_ALWAYS_INLINE void
709 : store(__pointer_type __p,
710 : memory_order __m = memory_order_seq_cst) noexcept
711 : {
712 : memory_order __b = __m & __memory_order_mask;
713 :
714 : __glibcxx_assert(__b != memory_order_acquire);
715 : __glibcxx_assert(__b != memory_order_acq_rel);
716 : __glibcxx_assert(__b != memory_order_consume);
717 :
718 : __atomic_store_n(&_M_p, __p, int(__m));
719 : }
720 :
721 : _GLIBCXX_ALWAYS_INLINE void
722 : store(__pointer_type __p,
723 : memory_order __m = memory_order_seq_cst) volatile noexcept
724 : {
725 : memory_order __b = __m & __memory_order_mask;
726 : __glibcxx_assert(__b != memory_order_acquire);
727 : __glibcxx_assert(__b != memory_order_acq_rel);
728 : __glibcxx_assert(__b != memory_order_consume);
729 :
730 : __atomic_store_n(&_M_p, __p, int(__m));
731 : }
732 :
733 : _GLIBCXX_ALWAYS_INLINE __pointer_type
734 : load(memory_order __m = memory_order_seq_cst) const noexcept
735 : {
736 : memory_order __b = __m & __memory_order_mask;
737 : __glibcxx_assert(__b != memory_order_release);
738 : __glibcxx_assert(__b != memory_order_acq_rel);
739 :
740 : return __atomic_load_n(&_M_p, int(__m));
741 : }
742 :
743 : _GLIBCXX_ALWAYS_INLINE __pointer_type
744 : load(memory_order __m = memory_order_seq_cst) const volatile noexcept
745 : {
746 : memory_order __b = __m & __memory_order_mask;
747 : __glibcxx_assert(__b != memory_order_release);
748 : __glibcxx_assert(__b != memory_order_acq_rel);
749 :
750 : return __atomic_load_n(&_M_p, int(__m));
751 : }
752 :
753 : _GLIBCXX_ALWAYS_INLINE __pointer_type
754 : exchange(__pointer_type __p,
755 : memory_order __m = memory_order_seq_cst) noexcept
756 : {
757 : return __atomic_exchange_n(&_M_p, __p, int(__m));
758 : }
759 :
760 :
761 : _GLIBCXX_ALWAYS_INLINE __pointer_type
762 : exchange(__pointer_type __p,
763 : memory_order __m = memory_order_seq_cst) volatile noexcept
764 : {
765 : return __atomic_exchange_n(&_M_p, __p, int(__m));
766 : }
767 :
768 : _GLIBCXX_ALWAYS_INLINE bool
769 : compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
770 : memory_order __m1,
771 : memory_order __m2) noexcept
772 : {
773 : memory_order __b2 = __m2 & __memory_order_mask;
774 : memory_order __b1 = __m1 & __memory_order_mask;
775 : __glibcxx_assert(__b2 != memory_order_release);
776 : __glibcxx_assert(__b2 != memory_order_acq_rel);
777 : __glibcxx_assert(__b2 <= __b1);
778 :
779 : return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
780 : int(__m1), int(__m2));
781 : }
782 :
783 : _GLIBCXX_ALWAYS_INLINE bool
784 : compare_exchange_strong(__pointer_type& __p1, __pointer_type __p2,
785 : memory_order __m1,
786 : memory_order __m2) volatile noexcept
787 : {
788 : memory_order __b2 = __m2 & __memory_order_mask;
789 : memory_order __b1 = __m1 & __memory_order_mask;
790 :
791 : __glibcxx_assert(__b2 != memory_order_release);
792 : __glibcxx_assert(__b2 != memory_order_acq_rel);
793 : __glibcxx_assert(__b2 <= __b1);
794 :
795 : return __atomic_compare_exchange_n(&_M_p, &__p1, __p2, 0,
796 : int(__m1), int(__m2));
797 : }
798 :
799 : _GLIBCXX_ALWAYS_INLINE __pointer_type
800 : fetch_add(ptrdiff_t __d,
801 : memory_order __m = memory_order_seq_cst) noexcept
802 : { return __atomic_fetch_add(&_M_p, _M_type_size(__d), int(__m)); }
803 :
804 : _GLIBCXX_ALWAYS_INLINE __pointer_type
805 : fetch_add(ptrdiff_t __d,
806 : memory_order __m = memory_order_seq_cst) volatile noexcept
807 : { return __atomic_fetch_add(&_M_p, _M_type_size(__d), int(__m)); }
808 :
809 : _GLIBCXX_ALWAYS_INLINE __pointer_type
810 : fetch_sub(ptrdiff_t __d,
811 : memory_order __m = memory_order_seq_cst) noexcept
812 : { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), int(__m)); }
813 :
814 : _GLIBCXX_ALWAYS_INLINE __pointer_type
815 : fetch_sub(ptrdiff_t __d,
816 : memory_order __m = memory_order_seq_cst) volatile noexcept
817 : { return __atomic_fetch_sub(&_M_p, _M_type_size(__d), int(__m)); }
818 : };
819 :
820 : /// @} group atomics
821 :
822 : _GLIBCXX_END_NAMESPACE_VERSION
823 : } // namespace std
824 :
825 : #endif
|