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