1 /* atomic operations */
2
3 /*
4 * SPDX-FileCopyrightText: 1997-2015 Wind River Systems, Inc.
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #ifndef _BLE_MESH_ATOMIC_H_
10 #define _BLE_MESH_ATOMIC_H_
11
12 #include "mesh_types.h"
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18 typedef bt_mesh_atomic_t bt_mesh_atomic_val_t;
19
20 /**
21 * @defgroup atomic_apis Atomic Services APIs
22 * @ingroup kernel_apis
23 * @{
24 */
25
26 /**
27 *
28 * @brief Atomic increment.
29 *
30 * This routine performs an atomic increment by 1 on @a target.
31 *
32 * @param target Address of atomic variable.
33 *
34 * @return Previous value of @a target.
35 */
36 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_inc(bt_mesh_atomic_t * target)37 static inline bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target)
38 {
39 return bt_mesh_atomic_add(target, 1);
40 }
41 #else
42 extern bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target);
43 #endif
44
45 /**
46 *
47 * @brief Atomic decrement.
48 *
49 * This routine performs an atomic decrement by 1 on @a target.
50 *
51 * @param target Address of atomic variable.
52 *
53 * @return Previous value of @a target.
54 */
55 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_dec(bt_mesh_atomic_t * target)56 static inline bt_mesh_atomic_val_t bt_mesh_atomic_dec(bt_mesh_atomic_t *target)
57 {
58 return bt_mesh_atomic_sub(target, 1);
59 }
60 #else
61 extern bt_mesh_atomic_val_t bt_mesh_atomic_dec(bt_mesh_atomic_t *target);
62 #endif
63
64 /**
65 *
66 * @brief Atomic get.
67 *
68 * This routine performs an atomic read on @a target.
69 *
70 * @param target Address of atomic variable.
71 *
72 * @return Value of @a target.
73 */
74 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_get(const bt_mesh_atomic_t * target)75 static inline bt_mesh_atomic_val_t bt_mesh_atomic_get(const bt_mesh_atomic_t *target)
76 {
77 return __atomic_load_n(target, __ATOMIC_SEQ_CST);
78 }
79 #else
80 extern bt_mesh_atomic_val_t bt_mesh_atomic_get(const bt_mesh_atomic_t *target);
81 #endif
82
83 /**
84 *
85 * @brief Atomic get-and-set.
86 *
87 * This routine atomically sets @a target to @a value and returns
88 * the previous value of @a target.
89 *
90 * @param target Address of atomic variable.
91 * @param value Value to write to @a target.
92 *
93 * @return Previous value of @a target.
94 */
95 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_set(bt_mesh_atomic_t * target,bt_mesh_atomic_val_t value)96 static inline bt_mesh_atomic_val_t bt_mesh_atomic_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value)
97 {
98 /* This builtin, as described by Intel, is not a traditional
99 * test-and-set operation, but rather an atomic exchange operation. It
100 * writes value into *ptr, and returns the previous contents of *ptr.
101 */
102 return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
103 }
104 #else
105 extern bt_mesh_atomic_val_t bt_mesh_atomic_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value);
106 #endif
107
108 /**
109 *
110 * @brief Atomic bitwise inclusive OR.
111 *
112 * This routine atomically sets @a target to the bitwise inclusive OR of
113 * @a target and @a value.
114 *
115 * @param target Address of atomic variable.
116 * @param value Value to OR.
117 *
118 * @return Previous value of @a target.
119 */
120 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_or(bt_mesh_atomic_t * target,bt_mesh_atomic_val_t value)121 static inline bt_mesh_atomic_val_t bt_mesh_atomic_or(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value)
122 {
123 return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
124 }
125 #else
126 extern bt_mesh_atomic_val_t bt_mesh_atomic_or(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value);
127 #endif
128
129 /**
130 *
131 * @brief Atomic bitwise AND.
132 *
133 * This routine atomically sets @a target to the bitwise AND of @a target
134 * and @a value.
135 *
136 * @param target Address of atomic variable.
137 * @param value Value to AND.
138 *
139 * @return Previous value of @a target.
140 */
141 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_and(bt_mesh_atomic_t * target,bt_mesh_atomic_val_t value)142 static inline bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value)
143 {
144 return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
145 }
146 #else
147 extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value);
148 #endif
149
150 /**
151 * @brief Atomic CAS operation.
152 *
153 * This compares the contents of @a *target
154 * with the contents of @a excepted. If equal,
155 * the operation is a read-modify-write operation
156 * that writes @a new_val into @a *target and return true.
157 * If they are not equal, the operation is a read
158 * and return false.
159 *
160 * @param target Address of atomic variable.
161 * @param excepted Value of excepted.
162 * @param new_val Write if target value is equal to expected one.
163 *
164 * @return
165 * - true: Target value updated.
166 * - false: Target value not updated.
167 */
168 #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN
bt_mesh_atomic_cas(bt_mesh_atomic_t * target,bt_mesh_atomic_val_t excepted,bt_mesh_atomic_val_t new_val)169 static inline bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val)
170 {
171 return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
172 }
173 #else
174 extern bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val);
175 #endif
176
177 /**
178 * @cond INTERNAL_HIDDEN
179 */
180
181 #define BLE_MESH_ATOMIC_BITS (sizeof(bt_mesh_atomic_val_t) * 8)
182 #define BLE_MESH_ATOMIC_MASK(bit) (1 << ((bit) & (BLE_MESH_ATOMIC_BITS - 1)))
183 #define BLE_MESH_ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / BLE_MESH_ATOMIC_BITS))
184
185 /**
186 * INTERNAL_HIDDEN @endcond
187 */
188
189 /**
190 * @brief Define an array of atomic variables.
191 *
192 * This macro defines an array of atomic variables containing at least
193 * @a num_bits bits.
194 *
195 * @note
196 * If used from file scope, the bits of the array are initialized to zero;
197 * if used from within a function, the bits are left uninitialized.
198 *
199 * @param name Name of array of atomic variables.
200 * @param num_bits Number of bits needed.
201 */
202 #define BLE_MESH_ATOMIC_DEFINE(name, num_bits) \
203 bt_mesh_atomic_t name[1 + ((num_bits) - 1) / BLE_MESH_ATOMIC_BITS]
204
205 /**
206 * @brief Atomically test a bit.
207 *
208 * This routine tests whether bit number @a bit of @a target is set or not.
209 * The target may be a single atomic variable or an array of them.
210 *
211 * @param target Address of atomic variable or array.
212 * @param bit Bit number (starting from 0).
213 *
214 * @return 1 if the bit was set, 0 if it wasn't.
215 */
bt_mesh_atomic_test_bit(const bt_mesh_atomic_t * target,int bit)216 static inline int bt_mesh_atomic_test_bit(const bt_mesh_atomic_t *target, int bit)
217 {
218 bt_mesh_atomic_val_t val = bt_mesh_atomic_get(BLE_MESH_ATOMIC_ELEM(target, bit));
219
220 return (1 & (val >> (bit & (BLE_MESH_ATOMIC_BITS - 1))));
221 }
222
223 /**
224 * @brief Atomically test and clear a bit.
225 *
226 * Atomically clear bit number @a bit of @a target and return its old value.
227 * The target may be a single atomic variable or an array of them.
228 *
229 * @param target Address of atomic variable or array.
230 * @param bit Bit number (starting from 0).
231 *
232 * @return 1 if the bit was set, 0 if it wasn't.
233 */
bt_mesh_atomic_test_and_clear_bit(bt_mesh_atomic_t * target,int bit)234 static inline int bt_mesh_atomic_test_and_clear_bit(bt_mesh_atomic_t *target, int bit)
235 {
236 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
237 bt_mesh_atomic_val_t old;
238
239 old = bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
240
241 return (old & mask) != 0;
242 }
243
244 /**
245 * @brief Atomically set a bit.
246 *
247 * Atomically set bit number @a bit of @a target and return its old value.
248 * The target may be a single atomic variable or an array of them.
249 *
250 * @param target Address of atomic variable or array.
251 * @param bit Bit number (starting from 0).
252 *
253 * @return 1 if the bit was set, 0 if it wasn't.
254 */
bt_mesh_atomic_test_and_set_bit(bt_mesh_atomic_t * target,int bit)255 static inline int bt_mesh_atomic_test_and_set_bit(bt_mesh_atomic_t *target, int bit)
256 {
257 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
258 bt_mesh_atomic_val_t old;
259
260 old = bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
261
262 return (old & mask) != 0;
263 }
264
265 /**
266 * @brief Atomically clear a bit.
267 *
268 * Atomically clear bit number @a bit of @a target.
269 * The target may be a single atomic variable or an array of them.
270 *
271 * @param target Address of atomic variable or array.
272 * @param bit Bit number (starting from 0).
273 *
274 * @return N/A
275 */
bt_mesh_atomic_clear_bit(bt_mesh_atomic_t * target,int bit)276 static inline void bt_mesh_atomic_clear_bit(bt_mesh_atomic_t *target, int bit)
277 {
278 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
279
280 (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
281 }
282
283 /**
284 * @brief Atomically set a bit.
285 *
286 * Atomically set bit number @a bit of @a target.
287 * The target may be a single atomic variable or an array of them.
288 *
289 * @param target Address of atomic variable or array.
290 * @param bit Bit number (starting from 0).
291 *
292 * @return N/A
293 */
bt_mesh_atomic_set_bit(bt_mesh_atomic_t * target,int bit)294 static inline void bt_mesh_atomic_set_bit(bt_mesh_atomic_t *target, int bit)
295 {
296 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
297
298 (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
299 }
300
301 /**
302 * @brief Atomically set a bit to a given value.
303 *
304 * Atomically set bit number @a bit of @a target to value @a val.
305 * The target may be a single atomic variable or an array of them.
306 *
307 * @param target Address of atomic variable or array.
308 * @param bit Bit number (starting from 0).
309 * @param val true for 1, false for 0.
310 *
311 * @return N/A
312 */
bt_mesh_atomic_set_bit_to(bt_mesh_atomic_t * target,int bit,bool val)313 static inline void bt_mesh_atomic_set_bit_to(bt_mesh_atomic_t *target, int bit, bool val)
314 {
315 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
316
317 if (val) {
318 (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
319 } else {
320 (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
321 }
322 }
323
324 /**
325 * @}
326 */
327
328 #ifdef __cplusplus
329 }
330 #endif
331
332 #endif /* _BLE_MESH_ATOMIC_H_ */
333