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