Embedded Template Library 1.0
Loading...
Searching...
No Matches
atomic_gcc_sync.h
1/******************************************************************************
2The MIT License(MIT)
3
4Embedded Template Library.
5https://github.com/ETLCPP/etl
6https://www.etlcpp.com
7
8Copyright(c) 2017 John Wellbelove
9
10Permission is hereby granted, free of charge, to any person obtaining a copy
11of this software and associated documentation files(the "Software"), to deal
12in the Software without restriction, including without limitation the rights
13to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
14copies of the Software, and to permit persons to whom the Software is
15furnished to do so, subject to the following conditions :
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27******************************************************************************/
28
29#ifndef ETL_ATOMIC_GCC_SYNC_INCLUDED
30#define ETL_ATOMIC_GCC_SYNC_INCLUDED
31
32#include "../platform.h"
33#include "../char_traits.h"
34#include "../mutex.h"
35#include "../nullptr.h"
36#include "../static_assert.h"
37#include "../type_traits.h"
38
39#include <stdint.h>
40#include <string.h>
41
42// Select the atomic builtins based on the ARM5 version of the GCC compiler.
43#if defined(ETL_COMPILER_ARM5)
44 #define ETL_USE_SYNC_BUILTINS
45#endif
46
47// Select the atomic builtins based on the ARM6 version of the GCC compiler.
48#if defined(ETL_COMPILER_ARM6)
49 #if ETL_COMPILER_FULL_VERSION >= 40700
50 #define ETL_USE_ATOMIC_BUILTINS
51 #else
52 #define ETL_USE_SYNC_BUILTINS
53 #endif
54#endif
55
56// Select the atomic builtins based on the version of the GCC compiler.
57#if defined(ETL_COMPILER_GCC)
58 #if ETL_COMPILER_FULL_VERSION >= 40700
59 #define ETL_USE_ATOMIC_BUILTINS
60 #else
61 #define ETL_USE_SYNC_BUILTINS
62 #endif
63#endif
64
65// Select the atomic builtins based on the version of the Clang compiler.
66#if defined(ETL_COMPILER_CLANG)
67 #if ETL_COMPILER_FULL_VERSION >= 50000
68 #define ETL_USE_ATOMIC_BUILTINS
69 #else
70 #define ETL_USE_SYNC_BUILTINS
71 #endif
72#endif
73
74namespace etl
75{
76#if defined(ETL_USE_ATOMIC_BUILTINS)
77
78 #define ETL_BUILTIN_LOCK \
79 do { \
80 while (__atomic_test_and_set(&flag, etl::memory_order_seq_cst)) \
81 { \
82 } \
83 } while (0)
84 #define ETL_BUILTIN_UNLOCK \
85 do { \
86 __atomic_clear(&flag, etl::memory_order_seq_cst); \
87 } while (0)
88
89 //***************************************************************************
90 // Atomic type for pre C++11 GCC compilers that support the builtin '__atomic'
91 // functions. Only integral and pointer types are supported.
92 //***************************************************************************
93
94 typedef enum memory_order
95 {
96 memory_order_relaxed = __ATOMIC_RELAXED,
97 memory_order_consume = __ATOMIC_CONSUME,
98 memory_order_acquire = __ATOMIC_ACQUIRE,
99 memory_order_release = __ATOMIC_RELEASE,
100 memory_order_acq_rel = __ATOMIC_ACQ_REL,
101 memory_order_seq_cst = __ATOMIC_SEQ_CST
102 } memory_order;
103
104 template <bool Is_Always_Lock_Free>
105 struct atomic_traits
106 {
107 static ETL_CONSTANT bool is_always_lock_free = Is_Always_Lock_Free;
108 };
109
110 template <bool Is_Always_Lock_Free>
111 ETL_CONSTANT bool atomic_traits<Is_Always_Lock_Free>::is_always_lock_free;
112
113 //***************************************************************************
115 //***************************************************************************
116 template <typename T, bool integral_type = etl::is_integral<T>::value>
117 class atomic : public atomic_traits<integral_type>
118 {
119 public:
120
121 ETL_CONSTEXPR atomic()
122 : value(T())
123 {
124 }
125
126 ETL_CONSTEXPR atomic(T v)
127 : value(v)
128 {
129 }
130
131 // Assignment
132 T operator=(T v)
133 {
134 store(v);
135
136 return v;
137 }
138
139 T operator=(T v) volatile
140 {
141 store(v);
142
143 return v;
144 }
145
146 // Pre-increment
147 T operator++()
148 {
149 return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst);
150 }
151
152 T operator++() volatile
153 {
154 return __atomic_add_fetch(&value, 1, etl::memory_order_seq_cst);
155 }
156
157 // Post-increment
158 T operator++(int)
159 {
160 return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst);
161 }
162
163 T operator++(int) volatile
164 {
165 return __atomic_fetch_add(&value, 1, etl::memory_order_seq_cst);
166 }
167
168 // Pre-decrement
169 T operator--()
170 {
171 return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst);
172 }
173
174 T operator--() volatile
175 {
176 return __atomic_sub_fetch(&value, 1, etl::memory_order_seq_cst);
177 }
178
179 // Post-decrement
180 T operator--(int)
181 {
182 return __atomic_fetch_sub(&value, 1, etl::memory_order_seq_cst);
183 }
184
185 T operator--(int) volatile
186 {
187 return __atomic_fetch_sub(&value, 1, etl::memory_order_seq_cst);
188 }
189
190 // Add
191 T operator+=(T v)
192 {
193 return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst);
194 }
195
196 T operator+=(T v) volatile
197 {
198 return __atomic_fetch_add(&value, v, etl::memory_order_seq_cst);
199 }
200
201 // Subtract
202 T operator-=(T v)
203 {
204 return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst);
205 }
206
207 T operator-=(T v) volatile
208 {
209 return __atomic_fetch_sub(&value, v, etl::memory_order_seq_cst);
210 }
211
212 // And
213 T operator&=(T v)
214 {
215 return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst);
216 }
217
218 T operator&=(T v) volatile
219 {
220 return __atomic_fetch_and(&value, v, etl::memory_order_seq_cst);
221 }
222
223 // Or
224 T operator|=(T v)
225 {
226 return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst);
227 }
228
229 T operator|=(T v) volatile
230 {
231 return __atomic_fetch_or(&value, v, etl::memory_order_seq_cst);
232 }
233
234 // Exclusive or
235 T operator^=(T v)
236 {
237 return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst);
238 }
239
240 T operator^=(T v) volatile
241 {
242 return __atomic_fetch_xor(&value, v, etl::memory_order_seq_cst);
243 }
244
245 // Conversion operator
246 operator T() const
247 {
248 return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst);
249 }
250
251 operator T() volatile const
252 {
253 return __atomic_fetch_add(&value, 0, etl::memory_order_seq_cst);
254 }
255
256 // Is lock free?
257 bool is_lock_free() const
258 {
259 return true;
260 }
261
262 bool is_lock_free() const volatile
263 {
264 return true;
265 }
266
267 // Store
268 void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
269 {
270 __atomic_store_n(&value, v, order);
271 }
272
273 void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
274 {
275 __atomic_store_n(&value, v, order);
276 }
277
278 // Load
279 T load(etl::memory_order order = etl::memory_order_seq_cst) const
280 {
281 return __atomic_load_n(&value, order);
282 }
283
284 T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
285 {
286 return __atomic_load_n(&value, order);
287 }
288
289 // Fetch add
290 T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst)
291 {
292 return __atomic_fetch_add(&value, v, order);
293 }
294
295 T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
296 {
297 return __atomic_fetch_add(&value, v, order);
298 }
299
300 // Fetch subtract
301 T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst)
302 {
303 return __atomic_fetch_sub(&value, v, order);
304 }
305
306 T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
307 {
308 return __atomic_fetch_sub(&value, v, order);
309 }
310
311 // Fetch or
312 T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst)
313 {
314 return __atomic_fetch_or(&value, v, order);
315 }
316
317 T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
318 {
319 return __atomic_fetch_or(&value, v, order);
320 }
321
322 // Fetch and
323 T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst)
324 {
325 return __atomic_fetch_and(&value, v, order);
326 }
327
328 T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
329 {
330 return __atomic_fetch_and(&value, v, order);
331 }
332
333 // Fetch exclusive or
334 T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst)
335 {
336 return __atomic_fetch_xor(&value, v, order);
337 }
338
339 T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
340 {
341 return __atomic_fetch_xor(&value, v, order);
342 }
343
344 // Fetch max
345 T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst)
346 {
347 T old = load(order);
348
349 while (v > old)
350 {
351 if (compare_exchange_weak(old, v, order))
352 {
353 break;
354 }
355 }
356
357 return old;
358 }
359
360 T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
361 {
362 T old = load(order);
363
364 while (v > old)
365 {
366 if (compare_exchange_weak(old, v, order))
367 {
368 break;
369 }
370 }
371
372 return old;
373 }
374
375 // Fetch min
376 T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst)
377 {
378 T old = load(order);
379
380 while (v < old)
381 {
382 if (compare_exchange_weak(old, v, order))
383 {
384 break;
385 }
386 }
387
388 return old;
389 }
390
391 T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
392 {
393 T old = load(order);
394
395 while (v < old)
396 {
397 if (compare_exchange_weak(old, v, order))
398 {
399 break;
400 }
401 }
402
403 return old;
404 }
405
406 // Exchange
407 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst)
408 {
409 return __atomic_exchange_n(&value, v, order);
410 }
411
412 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
413 {
414 return __atomic_exchange_n(&value, v, order);
415 }
416
417 // Compare exchange weak
418 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
419 {
420 return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order);
421 }
422
423 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
424 {
425 return __atomic_compare_exchange_n(&value, &expected, desired, true, order, order);
426 }
427
428 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
429 {
430 return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure);
431 }
432
433 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
434 {
435 return __atomic_compare_exchange_n(&value, &expected, desired, true, success, failure);
436 }
437
438 // Compare exchange strong
439 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
440 {
441 return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order);
442 }
443
444 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
445 {
446 return __atomic_compare_exchange_n(&value, &expected, desired, false, order, order);
447 }
448
449 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
450 {
451 return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure);
452 }
453
454 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
455 {
456 return __atomic_compare_exchange_n(&value, &expected, desired, false, success, failure);
457 }
458
459 private:
460
461 atomic& operator=(const atomic&) ETL_DELETE;
462 atomic& operator=(const atomic&) volatile ETL_DELETE;
463
464 mutable T value;
465 };
466
467 //***************************************************************************
469 //***************************************************************************
470 template <typename T>
471 class atomic<T*, false> : public atomic_traits<true>
472 {
473 public:
474
475 ETL_CONSTEXPR atomic()
476 : value(0U)
477 {
478 }
479
480 atomic(T* v)
481 : value(uintptr_t(v))
482 {
483 }
484
485 // Assignment
486 T* operator=(T* v)
487 {
488 store(v);
489
490 return v;
491 }
492
493 T* operator=(T* v) volatile
494 {
495 store(v);
496
497 return v;
498 }
499
500 // Pre-increment
501 T* operator++()
502 {
503 return reinterpret_cast<T*>(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst));
504 }
505
506 T* operator++() volatile
507 {
508 return reinterpret_cast<T*>(__atomic_add_fetch(&value, sizeof(T), etl::memory_order_seq_cst));
509 }
510
511 // Post-increment
512 T* operator++(int)
513 {
514 return reinterpret_cast<T*>(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst));
515 }
516
517 T* operator++(int) volatile
518 {
519 return reinterpret_cast<T*>(__atomic_fetch_add(&value, sizeof(T), etl::memory_order_seq_cst));
520 }
521
522 // Pre-decrement
523 T* operator--()
524 {
525 return reinterpret_cast<T*>(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst));
526 }
527
528 T* operator--() volatile
529 {
530 return reinterpret_cast<T*>(__atomic_sub_fetch(&value, sizeof(T), etl::memory_order_seq_cst));
531 }
532
533 // Post-decrement
534 T* operator--(int)
535 {
536 return reinterpret_cast<T*>(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst));
537 }
538
539 T* operator--(int) volatile
540 {
541 return reinterpret_cast<T*>(__atomic_fetch_sub(&value, sizeof(T), etl::memory_order_seq_cst));
542 }
543
544 // Add
545 T* operator+=(ptrdiff_t v)
546 {
547 return reinterpret_cast<T*>(
548 __atomic_fetch_add(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), etl::memory_order_seq_cst));
549 }
550
551 T* operator+=(ptrdiff_t v) volatile
552 {
553 return reinterpret_cast<T*>(
554 __atomic_fetch_add(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), etl::memory_order_seq_cst));
555 }
556
557 // Subtract
558 T* operator-=(ptrdiff_t v)
559 {
560 return reinterpret_cast<T*>(
561 __atomic_fetch_sub(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), etl::memory_order_seq_cst));
562 }
563
564 T* operator-=(ptrdiff_t v) volatile
565 {
566 return reinterpret_cast<T*>(
567 __atomic_fetch_sub(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), etl::memory_order_seq_cst));
568 }
569
570 // Conversion operator
571 operator T*() const
572 {
573 return reinterpret_cast<T*>(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst));
574 }
575
576 operator T*() volatile const
577 {
578 return reinterpret_cast<T*>(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst));
579 }
580
581 // Is lock free?
582 bool is_lock_free() const
583 {
584 return true;
585 }
586
587 bool is_lock_free() const volatile
588 {
589 return true;
590 }
591
592 // Store
593 void store(T* v, etl::memory_order order = etl::memory_order_seq_cst)
594 {
595 __atomic_store_n(&value, uintptr_t(v), order);
596 }
597
598 void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
599 {
600 __atomic_store_n(&value, uintptr_t(v), order);
601 }
602
603 // Load
604 T* load(etl::memory_order order = etl::memory_order_seq_cst) const
605 {
606 return reinterpret_cast<T*>(__atomic_load_n(&value, order));
607 }
608
609 T* load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
610 {
611 return reinterpret_cast<T*>(__atomic_load_n(&value, order));
612 }
613
614 // Fetch add
615 T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
616 {
617 return reinterpret_cast<T*>(__atomic_fetch_add(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), order));
618 }
619
620 T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
621 {
622 return reinterpret_cast<T*>(__atomic_fetch_add(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), order));
623 }
624
625 // Fetch subtract
626 T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
627 {
628 return reinterpret_cast<T*>(__atomic_fetch_sub(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), order));
629 }
630
631 T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
632 {
633 return reinterpret_cast<T*>(__atomic_fetch_sub(&value, static_cast<uintptr_t>(v * static_cast<ptrdiff_t>(sizeof(T))), order));
634 }
635
636 // Exchange
637 T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst)
638 {
639 return reinterpret_cast<T*>(__atomic_exchange_n(&value, uintptr_t(v), order));
640 }
641
642 T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
643 {
644 return reinterpret_cast<T*>(__atomic_exchange_n(&value, uintptr_t(v), order));
645 }
646
647 // Compare exchange weak
648 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
649 {
650 uintptr_t expected_v = uintptr_t(expected);
651
652 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order);
653 }
654
655 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
656 {
657 uintptr_t expected_v = uintptr_t(expected);
658
659 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, order, order);
660 }
661
662 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
663 {
664 uintptr_t expected_v = uintptr_t(expected);
665
666 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure);
667 }
668
669 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
670 {
671 uintptr_t expected_v = uintptr_t(expected);
672
673 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), true, success, failure);
674 }
675
676 // Compare exchange strong
677 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
678 {
679 uintptr_t expected_v = uintptr_t(expected);
680
681 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order);
682 }
683
684 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
685 {
686 uintptr_t expected_v = uintptr_t(expected);
687
688 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, order, order);
689 }
690
691 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
692 {
693 uintptr_t expected_v = uintptr_t(expected);
694
695 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure);
696 }
697
698 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
699 {
700 uintptr_t expected_v = uintptr_t(expected);
701
702 return __atomic_compare_exchange_n(&value, &expected_v, uintptr_t(desired), false, success, failure);
703 }
704
705 private:
706
707 atomic& operator=(const atomic&) ETL_DELETE;
708 atomic& operator=(const atomic&) volatile ETL_DELETE;
709
710 mutable uintptr_t value;
711 };
712
713 //***************************************************************************
715 //***************************************************************************
716 template <>
717 class atomic<bool, true> : public atomic_traits<true>
718 {
719 public:
720
721 ETL_CONSTEXPR atomic()
722 : value(0U)
723 {
724 }
725
726 ETL_CONSTEXPR atomic(bool v)
727 : value(char(v))
728 {
729 }
730
731 // Assignment
732 bool operator=(bool v)
733 {
734 store(v);
735
736 return v;
737 }
738
739 bool operator=(bool v) volatile
740 {
741 store(v);
742
743 return v;
744 }
745
746 // Conversion operator
747 operator bool() const
748 {
749 return static_cast<bool>(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst));
750 }
751
752 operator bool() volatile const
753 {
754 return static_cast<bool>(__atomic_fetch_add(&value, 0, etl::memory_order_seq_cst));
755 }
756
757 // Is lock free?
758 bool is_lock_free() const
759 {
760 return true;
761 }
762
763 bool is_lock_free() const volatile
764 {
765 return true;
766 }
767
768 // Store
769 void store(bool v, etl::memory_order order = etl::memory_order_seq_cst)
770 {
771 __atomic_store_n(&value, char(v), order);
772 }
773
774 void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile
775 {
776 __atomic_store_n(&value, char(v), order);
777 }
778
779 // Load
780 bool load(etl::memory_order order = etl::memory_order_seq_cst) const
781 {
782 return static_cast<bool>(__atomic_load_n(&value, order));
783 }
784
785 bool load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
786 {
787 return static_cast<bool>(__atomic_load_n(&value, order));
788 }
789
790 // Exchange
791 bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst)
792 {
793 return static_cast<bool>(__atomic_exchange_n(&value, char(v), order));
794 }
795
796 bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile
797 {
798 return static_cast<bool>(__atomic_exchange_n(&value, char(v), order));
799 }
800
801 // Compare exchange weak
802 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst)
803 {
804 char expected_v = char(expected);
805 char desired_v = char(desired);
806
807 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order);
808 }
809
810 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
811 {
812 char expected_v = char(expected);
813 char desired_v = char(desired);
814
815 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, order, order);
816 }
817
818 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure)
819 {
820 char expected_v = char(expected);
821 char desired_v = char(desired);
822
823 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure);
824 }
825
826 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile
827 {
828 char expected_v = char(expected);
829 char desired_v = char(desired);
830
831 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, true, success, failure);
832 }
833
834 // Compare exchange strong
835 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst)
836 {
837 char expected_v = char(expected);
838 char desired_v = char(desired);
839
840 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order);
841 }
842
843 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
844 {
845 char expected_v = char(expected);
846 char desired_v = char(desired);
847
848 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, order, order);
849 }
850
851 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure)
852 {
853 char expected_v = char(expected);
854 char desired_v = char(desired);
855
856 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure);
857 }
858
859 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile
860 {
861 char expected_v = char(expected);
862 char desired_v = char(desired);
863
864 return __atomic_compare_exchange_n(&value, &expected_v, desired_v, false, success, failure);
865 }
866
867 private:
868
869 atomic& operator=(const atomic&) ETL_DELETE;
870 atomic& operator=(const atomic&) volatile ETL_DELETE;
871
872 mutable char value;
873 };
874
875 //***************************************************************************
878 //***************************************************************************
879 template <typename T>
880 class atomic<T, false> : public atomic_traits<false>
881 {
882 public:
883
884 ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
885 ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
886 ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
887 ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
888 ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
889 ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
890
891 atomic()
892 : flag(0)
893 , value(T())
894 {
895 }
896
897 atomic(T v)
898 : flag(0)
899 , value(v)
900 {
901 }
902
903 // Assignment
904 T operator=(T v)
905 {
906 store(v);
907
908 return v;
909 }
910
911 // Conversion operator
912 operator T() const
913 {
914 ETL_BUILTIN_LOCK;
915 T result = value;
916 ETL_BUILTIN_UNLOCK;
917
918 return result;
919 }
920
921 // Is lock free?
922 bool is_lock_free() const
923 {
924 return false;
925 }
926
927 // Store
928 void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
929 {
930 (void)order;
931 ETL_BUILTIN_LOCK;
932 value = v;
933 ETL_BUILTIN_UNLOCK;
934 }
935
936 // Load
937 T load(etl::memory_order order = etl::memory_order_seq_cst) const
938 {
939 (void)order;
940 ETL_BUILTIN_LOCK;
941 T result = value;
942 ETL_BUILTIN_UNLOCK;
943
944 return result;
945 }
946
947 // Exchange
948 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst)
949 {
950 (void)order;
951 ETL_BUILTIN_LOCK;
952 T result = value;
953 value = v;
954 ETL_BUILTIN_UNLOCK;
955
956 return result;
957 }
958
959 // Compare exchange weak
960 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
961 {
962 bool result;
963
964 (void)order;
965 ETL_BUILTIN_LOCK;
966 if (memcmp(&value, &expected, sizeof(T)) == 0)
967 {
968 value = desired;
969 result = true;
970 }
971 else
972 {
973 result = false;
974 }
975 ETL_BUILTIN_UNLOCK;
976
977 return result;
978 }
979
980 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
981 {
982 (void)success;
983 (void)failure;
984 return compare_exchange_weak(expected, desired);
985 }
986
987 // Compare exchange strong
988 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
989 {
990 (void)order;
991 return compare_exchange_weak(expected, desired);
992 }
993
994 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
995 {
996 (void)success;
997 (void)failure;
998 return compare_exchange_weak(expected, desired);
999 }
1000
1001 private:
1002
1003 atomic& operator=(const atomic&) ETL_DELETE;
1004 atomic& operator=(const atomic&) volatile ETL_DELETE;
1005
1006 mutable char flag;
1007 mutable T value;
1008 };
1009
1010 #undef ETL_BUILTIN_LOCK
1011 #undef ETL_BUILTIN_UNLOCK
1012
1013#endif
1014
1015#if defined(ETL_USE_SYNC_BUILTINS)
1016
1017 #define ETL_BUILTIN_LOCK \
1018 do { \
1019 while (__sync_lock_test_and_set(&flag, 1U)) \
1020 { \
1021 } \
1022 } while (0)
1023 #define ETL_BUILTIN_UNLOCK \
1024 do { \
1025 __sync_lock_release(&flag); \
1026 } while (0)
1027
1028 //***************************************************************************
1029 // Atomic type for pre C++11 GCC compilers that support the builtin '__sync'
1030 // functions. Only integral and pointer types are supported.
1031 //***************************************************************************
1032
1033 typedef enum memory_order
1034 {
1035 memory_order_relaxed,
1036 memory_order_consume,
1037 memory_order_acquire,
1038 memory_order_release,
1039 memory_order_acq_rel,
1040 memory_order_seq_cst
1041 } memory_order;
1042
1043 template <bool Is_Always_Lock_Free>
1044 struct atomic_traits
1045 {
1046 static ETL_CONSTANT bool is_always_lock_free = Is_Always_Lock_Free;
1047 };
1048
1049 template <bool Is_Always_Lock_Free>
1050 ETL_CONSTANT bool atomic_traits<Is_Always_Lock_Free>::is_always_lock_free;
1051
1052 //***************************************************************************
1054 //***************************************************************************
1055 template <typename T, bool integral_type = etl::is_integral<T>::value>
1056 class atomic : public atomic_traits<integral_type>
1057 {
1058 public:
1059
1060 ETL_STATIC_ASSERT(etl::is_integral<T>::value, "Only integral types are supported");
1061
1062 ETL_CONSTEXPR atomic()
1063 : value(0)
1064 {
1065 }
1066
1067 ETL_CONSTEXPR atomic(T v)
1068 : value(v)
1069 {
1070 }
1071
1072 // Assignment
1073 T operator=(T v)
1074 {
1075 store(v);
1076
1077 return v;
1078 }
1079
1080 T operator=(T v) volatile
1081 {
1082 store(v);
1083
1084 return v;
1085 }
1086
1087 // Pre-increment
1088 T operator++()
1089 {
1090 return __sync_add_and_fetch(&value, 1);
1091 }
1092
1093 T operator++() volatile
1094 {
1095 return __sync_add_and_fetch(&value, 1);
1096 }
1097
1098 // Post-increment
1099 T operator++(int)
1100 {
1101 return __sync_fetch_and_add(&value, 1);
1102 }
1103
1104 T operator++(int) volatile
1105 {
1106 return __sync_fetch_and_add(&value, 1);
1107 }
1108
1109 // Pre-decrement
1110 T operator--()
1111 {
1112 return __sync_sub_and_fetch(&value, 1);
1113 }
1114
1115 T operator--() volatile
1116 {
1117 return __sync_sub_and_fetch(&value, 1);
1118 }
1119
1120 // Post-decrement
1121 T operator--(int)
1122 {
1123 return __sync_fetch_and_sub(&value, 1);
1124 }
1125
1126 T operator--(int) volatile
1127 {
1128 return __sync_fetch_and_sub(&value, 1);
1129 }
1130
1131 // Add
1132 T operator+=(T v)
1133 {
1134 return __sync_fetch_and_add(&value, v);
1135 }
1136
1137 T operator+=(T v) volatile
1138 {
1139 return __sync_fetch_and_add(&value, v);
1140 }
1141
1142 // Subtract
1143 T operator-=(T v)
1144 {
1145 return __sync_fetch_and_sub(&value, v);
1146 }
1147
1148 T operator-=(T v) volatile
1149 {
1150 return __sync_fetch_and_sub(&value, v);
1151 }
1152
1153 // And
1154 T operator&=(T v)
1155 {
1156 return __sync_fetch_and_and(&value, v);
1157 }
1158
1159 T operator&=(T v) volatile
1160 {
1161 return __sync_fetch_and_and(&value, v);
1162 }
1163
1164 // Or
1165 T operator|=(T v)
1166 {
1167 return __sync_fetch_and_or(&value, v);
1168 }
1169
1170 T operator|=(T v) volatile
1171 {
1172 return __sync_fetch_and_or(&value, v);
1173 }
1174
1175 // Exclusive or
1176 T operator^=(T v)
1177 {
1178 return __sync_fetch_and_xor(&value, v);
1179 }
1180
1181 T operator^=(T v) volatile
1182 {
1183 return __sync_fetch_and_xor(&value, v);
1184 }
1185
1186 // Conversion operator
1187 operator T() const
1188 {
1189 return __sync_fetch_and_add(&value, 0);
1190 }
1191
1192 operator T() volatile const
1193 {
1194 return __sync_fetch_and_add(&value, 0);
1195 }
1196
1197 // Is lock free?
1198 bool is_lock_free() const
1199 {
1200 return true;
1201 }
1202
1203 bool is_lock_free() const volatile
1204 {
1205 return true;
1206 }
1207
1208 // Store
1209 void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
1210 {
1211 (void)order;
1212 (void)__sync_lock_test_and_set(&value, v);
1213 }
1214
1215 void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1216 {
1217 (void)order;
1218 (void)__sync_lock_test_and_set(&value, v);
1219 }
1220
1221 // Load
1222 T load(etl::memory_order order = etl::memory_order_seq_cst) const
1223 {
1224 (void)order;
1225 return __sync_fetch_and_add(&value, 0);
1226 }
1227
1228 T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
1229 {
1230 (void)order;
1231 return __sync_fetch_and_add(&value, 0);
1232 }
1233
1234 // Fetch add
1235 T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst)
1236 {
1237 (void)order;
1238 return __sync_fetch_and_add(&value, v);
1239 }
1240
1241 T fetch_add(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1242 {
1243 (void)order;
1244 return __sync_fetch_and_add(&value, v);
1245 }
1246
1247 // Fetch subtract
1248 T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst)
1249 {
1250 (void)order;
1251 return __sync_fetch_and_sub(&value, v);
1252 }
1253
1254 T fetch_sub(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1255 {
1256 (void)order;
1257 return __sync_fetch_and_sub(&value, v);
1258 }
1259
1260 // Fetch or
1261 T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst)
1262 {
1263 (void)order;
1264 return __sync_fetch_and_or(&value, v);
1265 }
1266
1267 T fetch_or(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1268 {
1269 (void)order;
1270 return __sync_fetch_and_or(&value, v);
1271 }
1272
1273 // Fetch and
1274 T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst)
1275 {
1276 (void)order;
1277 return __sync_fetch_and_and(&value, v);
1278 }
1279
1280 T fetch_and(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1281 {
1282 (void)order;
1283 return __sync_fetch_and_and(&value, v);
1284 }
1285
1286 // Fetch exclusive or
1287 T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst)
1288 {
1289 (void)order;
1290 return __sync_fetch_and_xor(&value, v);
1291 }
1292
1293 T fetch_xor(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1294 {
1295 (void)order;
1296 return __sync_fetch_and_xor(&value, v);
1297 }
1298
1299 // Fetch max
1300 T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst)
1301 {
1302 (void)order;
1303 T old = load(order);
1304
1305 while (v > old)
1306 {
1307 if (compare_exchange_weak(old, v, order))
1308 {
1309 break;
1310 }
1311 }
1312
1313 return old;
1314 }
1315
1316 T fetch_max(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1317 {
1318 (void)order;
1319 T old = load(order);
1320
1321 while (v > old)
1322 {
1323 if (compare_exchange_weak(old, v, order))
1324 {
1325 break;
1326 }
1327 }
1328
1329 return old;
1330 }
1331
1332 // Fetch min
1333 T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst)
1334 {
1335 (void)order;
1336 T old = load(order);
1337
1338 while (v < old)
1339 {
1340 if (compare_exchange_weak(old, v, order))
1341 {
1342 break;
1343 }
1344 }
1345
1346 return old;
1347 }
1348
1349 T fetch_min(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1350 {
1351 (void)order;
1352 T old = load(order);
1353
1354 while (v < old)
1355 {
1356 if (compare_exchange_weak(old, v, order))
1357 {
1358 break;
1359 }
1360 }
1361
1362 return old;
1363 }
1364
1365 // Exchange
1366 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst)
1367 {
1368 (void)order;
1369 return __sync_lock_test_and_set(&value, v);
1370 }
1371
1372 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1373 {
1374 (void)order;
1375 return __sync_lock_test_and_set(&value, v);
1376 }
1377
1378 // Compare exchange weak
1379 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
1380 {
1381 (void)order;
1382 T old = __sync_val_compare_and_swap(&value, expected, desired);
1383
1384 if (old == expected)
1385 {
1386 return true;
1387 }
1388 else
1389 {
1390 expected = old;
1391 return false;
1392 }
1393 }
1394
1395 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
1396 {
1397 (void)order;
1398 T old = __sync_val_compare_and_swap(&value, expected, desired);
1399
1400 if (old == expected)
1401 {
1402 return true;
1403 }
1404 else
1405 {
1406 expected = old;
1407 return false;
1408 }
1409 }
1410
1411 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
1412 {
1413 (void)success;
1414 (void)failure;
1415 T old = __sync_val_compare_and_swap(&value, expected, desired);
1416
1417 if (old == expected)
1418 {
1419 return true;
1420 }
1421 else
1422 {
1423 expected = old;
1424 return false;
1425 }
1426 }
1427
1428 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
1429 {
1430 (void)success;
1431 (void)failure;
1432 T old = __sync_val_compare_and_swap(&value, expected, desired);
1433
1434 if (old == expected)
1435 {
1436 return true;
1437 }
1438 else
1439 {
1440 expected = old;
1441 return false;
1442 }
1443 }
1444
1445 // Compare exchange strong
1446 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
1447 {
1448 (void)order;
1449 T old = expected;
1450
1451 while (!compare_exchange_weak(old, desired))
1452 {
1453 if (memcmp(&old, &expected, sizeof(T)))
1454 {
1455 expected = old;
1456 return false;
1457 }
1458 }
1459
1460 return true;
1461 }
1462
1463 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
1464 {
1465 (void)order;
1466 T old = expected;
1467
1468 while (!compare_exchange_weak(old, desired))
1469 {
1470 if (memcmp(&old, &expected, sizeof(T)))
1471 {
1472 expected = old;
1473 return false;
1474 }
1475 }
1476
1477 return true;
1478 }
1479
1480 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
1481 {
1482 (void)success;
1483 (void)failure;
1484 T old = expected;
1485
1486 while (!compare_exchange_weak(old, desired))
1487 {
1488 if (memcmp(&old, &expected, sizeof(T)))
1489 {
1490 expected = old;
1491 return false;
1492 }
1493 }
1494
1495 return true;
1496 }
1497
1498 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
1499 {
1500 (void)success;
1501 (void)failure;
1502 T old = expected;
1503
1504 while (!compare_exchange_weak(old, desired))
1505 {
1506 if (memcmp(&old, &expected, sizeof(T)))
1507 {
1508 expected = old;
1509 return false;
1510 }
1511 }
1512
1513 return true;
1514 }
1515
1516 private:
1517
1518 atomic& operator=(const atomic&) ETL_DELETE;
1519 atomic& operator=(const atomic&) volatile ETL_DELETE;
1520
1521 mutable volatile T value;
1522 };
1523
1524 //***************************************************************************
1526 //***************************************************************************
1527 template <typename T>
1528 class atomic<T*, false> : public atomic_traits<true>
1529 {
1530 public:
1531
1532 ETL_CONSTEXPR atomic()
1533 : value(0U)
1534 {
1535 }
1536
1537 atomic(T* v)
1538 : value(uintptr_t(v))
1539 {
1540 }
1541
1542 // Assignment
1543 T* operator=(T* v)
1544 {
1545 store(v);
1546
1547 return v;
1548 }
1549
1550 T* operator=(T* v) volatile
1551 {
1552 store(v);
1553
1554 return v;
1555 }
1556
1557 // Pre-increment
1558 T* operator++()
1559 {
1560 return reinterpret_cast<T*>(__sync_add_and_fetch(&value, sizeof(T)));
1561 }
1562
1563 T* operator++() volatile
1564 {
1565 return reinterpret_cast<T*>(__sync_add_and_fetch(&value, sizeof(T)));
1566 }
1567
1568 // Post-increment
1569 T* operator++(int)
1570 {
1571 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, sizeof(T)));
1572 }
1573
1574 T* operator++(int) volatile
1575 {
1576 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, sizeof(T)));
1577 }
1578
1579 // Pre-decrement
1580 T* operator--()
1581 {
1582 return reinterpret_cast<T*>(__sync_sub_and_fetch(&value, sizeof(T)));
1583 }
1584
1585 T* operator--() volatile
1586 {
1587 return reinterpret_cast<T*>(__sync_sub_and_fetch(&value, sizeof(T)));
1588 }
1589
1590 // Post-decrement
1591 T* operator--(int)
1592 {
1593 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, sizeof(T)));
1594 }
1595
1596 T* operator--(int) volatile
1597 {
1598 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, sizeof(T)));
1599 }
1600
1601 // Add
1602 T* operator+=(ptrdiff_t v)
1603 {
1604 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, v * sizeof(T)));
1605 }
1606
1607 T* operator+=(ptrdiff_t v) volatile
1608 {
1609 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, v * sizeof(T)));
1610 }
1611
1612 // Subtract
1613 T* operator-=(ptrdiff_t v)
1614 {
1615 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, v * sizeof(T)));
1616 }
1617
1618 T* operator-=(ptrdiff_t v) volatile
1619 {
1620 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, v * sizeof(T)));
1621 }
1622
1623 // Conversion operator
1624 operator T*() const
1625 {
1626 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, 0));
1627 }
1628
1629 operator T*() volatile const
1630 {
1631 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, 0));
1632 }
1633
1634 // Is lock free?
1635 bool is_lock_free() const
1636 {
1637 return true;
1638 }
1639
1640 bool is_lock_free() const volatile
1641 {
1642 return true;
1643 }
1644
1645 // Store
1646 void store(T* v, etl::memory_order order = etl::memory_order_seq_cst)
1647 {
1648 __sync_lock_test_and_set(&value, uintptr_t(v));
1649 }
1650
1651 void store(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1652 {
1653 __sync_lock_test_and_set(&value, uintptr_t(v));
1654 }
1655
1656 // Load
1657 T* load(etl::memory_order order = etl::memory_order_seq_cst) const
1658 {
1659 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, 0));
1660 }
1661
1662 T* load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
1663 {
1664 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, 0));
1665 }
1666
1667 // Fetch add
1668 T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
1669 {
1670 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, v));
1671 }
1672
1673 T* fetch_add(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1674 {
1675 return reinterpret_cast<T*>(__sync_fetch_and_add(&value, v));
1676 }
1677
1678 // Fetch subtract
1679 T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst)
1680 {
1681 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, v));
1682 }
1683
1684 T* fetch_sub(ptrdiff_t v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1685 {
1686 return reinterpret_cast<T*>(__sync_fetch_and_sub(&value, v));
1687 }
1688
1689 // Exchange
1690 T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst)
1691 {
1692 return reinterpret_cast<T*>(__sync_lock_test_and_set(&value, uintptr_t(v)));
1693 }
1694
1695 T* exchange(T* v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1696 {
1697 return reinterpret_cast<T*>(__sync_lock_test_and_set(&value, uintptr_t(v)));
1698 }
1699
1700 // Compare exchange weak
1701 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
1702 {
1703 T* old = reinterpret_cast<T*>(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired)));
1704
1705 if (old == expected)
1706 {
1707 return true;
1708 }
1709 else
1710 {
1711 expected = old;
1712 return false;
1713 }
1714 }
1715
1716 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
1717 {
1718 T* old = reinterpret_cast<T*>(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired)));
1719
1720 if (old == expected)
1721 {
1722 return true;
1723 }
1724 else
1725 {
1726 expected = old;
1727 return false;
1728 }
1729 }
1730
1731 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
1732 {
1733 T* old = reinterpret_cast<T*>(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired)));
1734
1735 if (old == expected)
1736 {
1737 return true;
1738 }
1739 else
1740 {
1741 expected = old;
1742 return false;
1743 }
1744 }
1745
1746 bool compare_exchange_weak(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
1747 {
1748 T* old = reinterpret_cast<T*>(__sync_val_compare_and_swap(&value, uintptr_t(expected), uintptr_t(desired)));
1749
1750 if (old == expected)
1751 {
1752 return true;
1753 }
1754 else
1755 {
1756 expected = old;
1757 return false;
1758 }
1759 }
1760
1761 // Compare exchange strong
1762 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst)
1763 {
1764 T* old = expected;
1765
1766 while (!compare_exchange_weak(old, desired))
1767 {
1768 if (memcmp(&old, &expected, sizeof(T*)))
1769 {
1770 expected = old;
1771 return false;
1772 }
1773 }
1774
1775 return true;
1776 }
1777
1778 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
1779 {
1780 T* old = expected;
1781
1782 while (!compare_exchange_weak(old, desired))
1783 {
1784 if (memcmp(&old, &expected, sizeof(T*)))
1785 {
1786 expected = old;
1787 return false;
1788 }
1789 }
1790
1791 return true;
1792 }
1793
1794 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure)
1795 {
1796 T* old = expected;
1797
1798 while (!compare_exchange_weak(old, desired))
1799 {
1800 if (memcmp(&old, &expected, sizeof(T*)))
1801 {
1802 expected = old;
1803 return false;
1804 }
1805 }
1806
1807 return true;
1808 }
1809
1810 bool compare_exchange_strong(T*& expected, T* desired, etl::memory_order success, etl::memory_order failure) volatile
1811 {
1812 T* old = expected;
1813
1814 while (!compare_exchange_weak(old, desired))
1815 {
1816 if (memcmp(&old, &expected, sizeof(T*)))
1817 {
1818 expected = old;
1819 return false;
1820 }
1821 }
1822
1823 return true;
1824 }
1825
1826 private:
1827
1828 atomic& operator=(const atomic&) ETL_DELETE;
1829 atomic& operator=(const atomic&) volatile ETL_DELETE;
1830
1831 mutable uintptr_t value;
1832 };
1833
1834 //***************************************************************************
1836 //***************************************************************************
1837 template <>
1838 class atomic<bool, true> : public atomic_traits<true>
1839 {
1840 public:
1841
1842 ETL_CONSTEXPR atomic()
1843 : value(0U)
1844 {
1845 }
1846
1847 ETL_CONSTEXPR atomic(bool v)
1848 : value(char(v))
1849 {
1850 }
1851
1852 // Assignment
1853 bool operator=(bool v)
1854 {
1855 store(v);
1856
1857 return v;
1858 }
1859
1860 bool operator=(bool v) volatile
1861 {
1862 store(v);
1863
1864 return v;
1865 }
1866
1867 // Conversion operator
1868 operator bool() const
1869 {
1870 return static_cast<bool>(__sync_fetch_and_add(&value, 0));
1871 }
1872
1873 operator bool() volatile const
1874 {
1875 return static_cast<bool>(__sync_fetch_and_add(&value, 0));
1876 }
1877
1878 // Is lock free?
1879 bool is_lock_free() const
1880 {
1881 return true;
1882 }
1883
1884 bool is_lock_free() const volatile
1885 {
1886 return true;
1887 }
1888
1889 // Store
1890 void store(bool v, etl::memory_order order = etl::memory_order_seq_cst)
1891 {
1892 __sync_lock_test_and_set(&value, char(v));
1893 }
1894
1895 void store(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1896 {
1897 __sync_lock_test_and_set(&value, char(v));
1898 }
1899
1900 // Load
1901 bool load(etl::memory_order order = etl::memory_order_seq_cst) const
1902 {
1903 return static_cast<bool>(__sync_fetch_and_add(&value, 0));
1904 }
1905
1906 bool load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
1907 {
1908 return static_cast<bool>(__sync_fetch_and_add(&value, 0));
1909 }
1910
1911 // Exchange
1912 bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst)
1913 {
1914 return static_cast<bool>(__sync_lock_test_and_set(&value, char(v)));
1915 }
1916
1917 bool exchange(bool v, etl::memory_order order = etl::memory_order_seq_cst) volatile
1918 {
1919 return static_cast<bool>(__sync_lock_test_and_set(&value, char(v)));
1920 }
1921
1922 // Compare exchange weak
1923 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst)
1924 {
1925 bool old = static_cast<bool>(__sync_val_compare_and_swap(&value, char(expected), char(desired)));
1926
1927 if (old == expected)
1928 {
1929 return true;
1930 }
1931 else
1932 {
1933 expected = old;
1934 return false;
1935 }
1936 }
1937
1938 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
1939 {
1940 bool old = static_cast<bool>(__sync_val_compare_and_swap(&value, char(expected), char(desired)));
1941
1942 if (old == expected)
1943 {
1944 return true;
1945 }
1946 else
1947 {
1948 expected = old;
1949 return false;
1950 }
1951 }
1952
1953 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure)
1954 {
1955 bool old = static_cast<bool>(__sync_val_compare_and_swap(&value, char(expected), char(desired)));
1956
1957 if (old == expected)
1958 {
1959 return true;
1960 }
1961 else
1962 {
1963 expected = old;
1964 return false;
1965 }
1966 }
1967
1968 bool compare_exchange_weak(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile
1969 {
1970 bool old = static_cast<bool>(__sync_val_compare_and_swap(&value, char(expected), char(desired)));
1971
1972 if (old == expected)
1973 {
1974 return true;
1975 }
1976 else
1977 {
1978 expected = old;
1979 return false;
1980 }
1981 }
1982
1983 // Compare exchange strong
1984 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst)
1985 {
1986 bool old = expected;
1987
1988 while (!compare_exchange_weak(old, desired))
1989 {
1990 if (memcmp(&old, &expected, sizeof(bool)))
1991 {
1992 expected = old;
1993 return false;
1994 }
1995 }
1996
1997 return true;
1998 }
1999
2000 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
2001 {
2002 bool old = expected;
2003
2004 while (!compare_exchange_weak(old, desired))
2005 {
2006 if (memcmp(&old, &expected, sizeof(bool)))
2007 {
2008 expected = old;
2009 return false;
2010 }
2011 }
2012
2013 return true;
2014 }
2015
2016 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure)
2017 {
2018 bool old = expected;
2019
2020 while (!compare_exchange_weak(old, desired))
2021 {
2022 if (memcmp(&old, &expected, sizeof(bool)))
2023 {
2024 expected = old;
2025 return false;
2026 }
2027 }
2028
2029 return true;
2030 }
2031
2032 bool compare_exchange_strong(bool& expected, bool desired, etl::memory_order success, etl::memory_order failure) volatile
2033 {
2034 bool old = expected;
2035
2036 while (!compare_exchange_weak(old, desired))
2037 {
2038 if (memcmp(&old, &expected, sizeof(bool)))
2039 {
2040 expected = old;
2041 return false;
2042 }
2043 }
2044
2045 return true;
2046 }
2047
2048 private:
2049
2050 atomic& operator=(const atomic&) ETL_DELETE;
2051 atomic& operator=(const atomic&) volatile ETL_DELETE;
2052
2053 mutable char value;
2054 };
2055
2056 //***************************************************************************
2059 //***************************************************************************
2060 template <typename T>
2061 class atomic<T, false> : public atomic_traits<false>
2062 {
2063 public:
2064
2065 ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
2066 ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
2067 ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
2068 ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
2069 ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
2070 ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
2071
2072 atomic()
2073 : flag(0)
2074 , value(T())
2075 {
2076 }
2077
2078 atomic(T v)
2079 : flag(0)
2080 , value(v)
2081 {
2082 }
2083
2084 // Assignment
2085 T operator=(T v)
2086 {
2087 store(v);
2088
2089 return v;
2090 }
2091
2092 // Conversion operator
2093 operator T() const
2094 {
2095 ETL_BUILTIN_LOCK;
2096 T result = value;
2097 ETL_BUILTIN_UNLOCK;
2098
2099 return result;
2100 }
2101
2102 // Is lock free?
2103 bool is_lock_free() const
2104 {
2105 return false;
2106 }
2107
2108 // Store
2109 void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
2110 {
2111 ETL_BUILTIN_LOCK;
2112 value = v;
2113 ETL_BUILTIN_UNLOCK;
2114 }
2115
2116 // Load
2117 T load(etl::memory_order order = etl::memory_order_seq_cst) const
2118 {
2119 ETL_BUILTIN_LOCK;
2120 T result = value;
2121 ETL_BUILTIN_UNLOCK;
2122
2123 return result;
2124 }
2125
2126 // Exchange
2127 T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst)
2128 {
2129 ETL_BUILTIN_LOCK;
2130 T result = value;
2131 value = v;
2132 ETL_BUILTIN_UNLOCK;
2133
2134 return result;
2135 }
2136
2137 // Compare exchange weak
2138 bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
2139 {
2140 bool result;
2141
2142 ETL_BUILTIN_LOCK;
2143 if (memcmp(&value, &expected, sizeof(T)) == 0)
2144 {
2145 value = desired;
2146 result = true;
2147 }
2148 else
2149 {
2150 result = false;
2151 }
2152 ETL_BUILTIN_UNLOCK;
2153
2154 return result;
2155 }
2156
2157 bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
2158 {
2159 return compare_exchange_weak(expected, desired);
2160 }
2161
2162 // Compare exchange strong
2163 bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
2164 {
2165 return compare_exchange_weak(expected, desired);
2166 }
2167
2168 bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
2169 {
2170 return compare_exchange_weak(expected, desired);
2171 }
2172
2173 private:
2174
2175 atomic& operator=(const atomic&) ETL_DELETE;
2176 atomic& operator=(const atomic&) volatile ETL_DELETE;
2177
2178 mutable char flag;
2179 mutable T value;
2180 };
2181
2182 #undef ETL_SYNC_BUILTIN_LOCK
2183 #undef ETL_SYNC_BUILTIN_UNLOCK
2184
2185#endif
2186
2187 typedef etl::atomic<bool> atomic_bool;
2188 typedef etl::atomic<char> atomic_char;
2189 typedef etl::atomic<signed char> atomic_schar;
2190 typedef etl::atomic<unsigned char> atomic_uchar;
2191 typedef etl::atomic<short> atomic_short;
2192 typedef etl::atomic<unsigned short> atomic_ushort;
2193 typedef etl::atomic<int> atomic_int;
2194 typedef etl::atomic<unsigned int> atomic_uint;
2195 typedef etl::atomic<long> atomic_long;
2196 typedef etl::atomic<unsigned long> atomic_ulong;
2197 typedef etl::atomic<long long> atomic_llong;
2198 typedef etl::atomic<unsigned long long> atomic_ullong;
2199 typedef etl::atomic<wchar_t> atomic_wchar_t;
2200#if ETL_HAS_NATIVE_CHAR8_T
2201 typedef etl::atomic<char8_t> atomic_char8_t;
2202#endif
2203#if ETL_HAS_NATIVE_CHAR16_T
2204 typedef etl::atomic<char16_t> atomic_char16_t;
2205#endif
2206#if ETL_HAS_NATIVE_CHAR32_T
2207 typedef etl::atomic<char32_t> atomic_char32_t;
2208#endif
2209#if ETL_USING_8BIT_TYPES
2210 typedef etl::atomic<uint8_t> atomic_uint8_t;
2211 typedef etl::atomic<int8_t> atomic_int8_t;
2212#endif
2213 typedef etl::atomic<uint16_t> atomic_uint16_t;
2214 typedef etl::atomic<int16_t> atomic_int16_t;
2215 typedef etl::atomic<uint32_t> atomic_uint32_t;
2216 typedef etl::atomic<int32_t> atomic_int32_t;
2217#if ETL_USING_64BIT_TYPES
2218 typedef etl::atomic<uint64_t> atomic_uint64_t;
2219 typedef etl::atomic<int64_t> atomic_int64_t;
2220#endif
2221 typedef etl::atomic<int_least8_t> atomic_int_least8_t;
2222 typedef etl::atomic<uint_least8_t> atomic_uint_least8_t;
2223 typedef etl::atomic<int_least16_t> atomic_int_least16_t;
2224 typedef etl::atomic<uint_least16_t> atomic_uint_least16_t;
2225 typedef etl::atomic<int_least32_t> atomic_int_least32_t;
2226 typedef etl::atomic<uint_least32_t> atomic_uint_least32_t;
2227#if ETL_USING_64BIT_TYPES
2228 typedef etl::atomic<int_least64_t> atomic_int_least64_t;
2229 typedef etl::atomic<uint_least64_t> atomic_uint_least64_t;
2230#endif
2231 typedef etl::atomic<int_fast8_t> atomic_int_fast8_t;
2232 typedef etl::atomic<uint_fast8_t> atomic_uint_fast8_t;
2233 typedef etl::atomic<int_fast16_t> atomic_int_fast16_t;
2234 typedef etl::atomic<uint_fast16_t> atomic_uint_fast16_t;
2235 typedef etl::atomic<int_fast32_t> atomic_int_fast32_t;
2236 typedef etl::atomic<uint_fast32_t> atomic_uint_fast32_t;
2237#if ETL_USING_64BIT_TYPES
2238 typedef etl::atomic<int_fast64_t> atomic_int_fast64_t;
2239 typedef etl::atomic<uint_fast64_t> atomic_uint_fast64_t;
2240#endif
2241 typedef etl::atomic<intptr_t> atomic_intptr_t;
2242 typedef etl::atomic<uintptr_t> atomic_uintptr_t;
2243 typedef etl::atomic<size_t> atomic_size_t;
2244 typedef etl::atomic<ptrdiff_t> atomic_ptrdiff_t;
2245 typedef etl::atomic<intmax_t> atomic_intmax_t;
2246 typedef etl::atomic<uintmax_t> atomic_uintmax_t;
2247} // namespace etl
2248
2249#endif
Definition atomic_std.h:54
Expected type.
Definition expected.h:257
Definition absolute.h:40
T exchange(T &object, const T &new_value)
exchange (const)
Definition utility.h:498
etl::byte & operator^=(etl::byte &lhs, etl::byte rhs)
Exclusive or equals.
Definition byte.h:290
etl::byte & operator|=(etl::byte &lhs, etl::byte rhs)
Or equals.
Definition byte.h:274
etl::byte & operator&=(etl::byte &lhs, etl::byte rhs)
And equals.
Definition byte.h:282