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