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