rtmlib
atomic_compat.h
Go to the documentation of this file.
1 /*
2  * rtmlib is a Real-Time Monitoring Library.
3  *
4  * Copyright (C) 2018-2020 AndrĂ© Pedro
5  *
6  * This file is part of rtmlib.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef _ATOMIC_COMPAT_H_
23 #define _ATOMIC_COMPAT_H_
24 
25 // Architecture dependent macros for atomic operations
26 
27 /*
28  * There is a notable difference in the __HW__, __x86__ and __ARM_CM4__
29  * implementations. ARM macros implement atomic operations using
30  * Load-link/store-conditional instructions, x86 uses compare-exchange, and __HW__
31  * supports hardware synthesis.
32  *
33  * The implementation of rtmlib in ARM is quite restrictive. It ensures that any
34  * inter-living is detected from any source, e.g. shared memory and interrupts
35  * among cores. The x86 implementation is more relaxed and suffers from the ABA
36  * problem, since the B thread can change the value to the one expected by the A
37  * thread that already started the atomic operation. The implementation for
38  * hardware synthesis does not consider any concurrency.
39  */
40 
41 #ifdef __HW__
42 
43 typedef unsigned int uint32_t;
44 
45 #elif defined(ARM_CM4_FP)
46 
47 #include <ARMCM4_FP.h>
48 
49 #include <atomic>
50 
51 #define ATOMIC_begin(expression, dest) \
52  uint32_t __lst_; \
53  __DMB(); \
54  do { \
55  __lst_ = expression __LDREXW((uint32_t *)dest);
56 
57 #define ATOMIC_end(dest) \
58  } \
59  while (__STREXW(__lst_, (uint32_t *)dest)) \
60  ;
61 
62 #define DMB __DMB();
63 #define DSB __DSB();
64 #define ISB __ISB();
65 
66 #define FRAME_ADDRESS frame_address
67 
68 #define OLD_FRAME_ADDRESS __old_value32
69 
70 #define FRAME_ADDRESS_type std::atomic<uint32_t>
71 
72 #define FRAME_ADDRESS_subtype uint32_t
73 
74 #define ATOMIC_begin_VALUE64(dest) \
75  bool fail = false; \
76  uint32_t OLD_FRAME_ADDRESS = (uint32_t)std::atomic_load(&dest); \
77  do { \
78  if (fail) { \
79  pthread_yield(); \
80  }
81 
82 #define ATOMIC_end_VALUE64(new_value, dest) \
83  } \
84  while ((fail = !std::atomic_compare_exchange_strong( \
85  &dest, &OLD_FRAME_ADDRESS, (uint32_t)new_value))) \
86  ;
87 
88 #define ATOMIC_begin_VALUE64_NOEXCHANGE(dest) \
89  uint32_t OLD_FRAME_ADDRESS = (uint32_t)std::atomic_load(&dest); \
90  do {
91 
92 #define ATOMIC_end_VALUE64_NOEXCHANGE(dest) \
93  } \
94  while (!(std::atomic_load(&dest) == OLD_FRAME_ADDRESS)) \
95  ;
96 
97 #define NATIVE_POINTER_TYPE uint32_t
98 #define NATIVE_ATOMIC_POINTER uint32_t
99 
100 #elif defined(__x86__) || defined(__x86_64__)
101 
102 #include <atomic>
103 
104 #define DMB
105 
106 #define FRAME_ADDRESS __counter
107 
108 #define OLD_FRAME_ADDRESS __old_value64
109 
110 #define FRAME_ADDRESS_type std::atomic<uint64_t>
111 
112 #define FRAME_ADDRESS_subtype uint64_t
113 
114 #define ATOMIC_begin_VALUE64(dest) \
115  bool fail = false; \
116  uint64_t OLD_FRAME_ADDRESS = (uint64_t)std::atomic_load(&dest); \
117  do { \
118  if (fail) { \
119  sched_yield(); \
120  }
121 
122 #define ATOMIC_end_VALUE64(new_value, dest) \
123  } \
124  while ((fail = !std::atomic_compare_exchange_strong( \
125  &dest, &OLD_FRAME_ADDRESS, (uint64_t)new_value))) \
126  ;
127 
128 #define ATOMIC_begin_VALUE64_NOEXCHANGE(dest) \
129  uint64_t OLD_FRAME_ADDRESS = (uint64_t)std::atomic_load(&dest); \
130  do {
131 
132 #define ATOMIC_end_VALUE64_NOEXCHANGE(dest) \
133  } \
134  while (!(std::atomic_load(&dest) == OLD_FRAME_ADDRESS)) \
135  ;
136 
137 #if defined(__x86_64__)
138 #define NATIVE_POINTER_TYPE uint64_t
139 typedef unsigned __int128 uint128_t;
140 #define NATIVE_ATOMIC_POINTER uint128_t
141 #else
142 #define USE_DOUBLE_CAS
143 #define NATIVE_POINTER_TYPE uint32_t
144 #define NATIVE_ATOMIC_POINTER uint64_t
145 #endif
146 
147 #else
148 
149 #warning "Atomic guarantees are not supported!"
150 
151 #define ATOMIC_begin()
152 #define ATOMIC_end()
153 
154 #endif
155 
156 #endif //_ATOMIC_COMPAT_H_