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 * @cond INTERNAL_HIDDEN
152 */
153
154 #define BLE_MESH_ATOMIC_BITS (sizeof(bt_mesh_atomic_val_t) * 8)
155 #define BLE_MESH_ATOMIC_MASK(bit) (1 << ((bit) & (BLE_MESH_ATOMIC_BITS - 1)))
156 #define BLE_MESH_ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / BLE_MESH_ATOMIC_BITS))
157
158 /**
159 * INTERNAL_HIDDEN @endcond
160 */
161
162 /**
163 * @brief Define an array of atomic variables.
164 *
165 * This macro defines an array of atomic variables containing at least
166 * @a num_bits bits.
167 *
168 * @note
169 * If used from file scope, the bits of the array are initialized to zero;
170 * if used from within a function, the bits are left uninitialized.
171 *
172 * @param name Name of array of atomic variables.
173 * @param num_bits Number of bits needed.
174 */
175 #define BLE_MESH_ATOMIC_DEFINE(name, num_bits) \
176 bt_mesh_atomic_t name[1 + ((num_bits) - 1) / BLE_MESH_ATOMIC_BITS]
177
178 /**
179 * @brief Atomically test a bit.
180 *
181 * This routine tests whether bit number @a bit of @a target is set or not.
182 * The target may be a single atomic variable or an array of them.
183 *
184 * @param target Address of atomic variable or array.
185 * @param bit Bit number (starting from 0).
186 *
187 * @return 1 if the bit was set, 0 if it wasn't.
188 */
bt_mesh_atomic_test_bit(const bt_mesh_atomic_t * target,int bit)189 static inline int bt_mesh_atomic_test_bit(const bt_mesh_atomic_t *target, int bit)
190 {
191 bt_mesh_atomic_val_t val = bt_mesh_atomic_get(BLE_MESH_ATOMIC_ELEM(target, bit));
192
193 return (1 & (val >> (bit & (BLE_MESH_ATOMIC_BITS - 1))));
194 }
195
196 /**
197 * @brief Atomically test and clear a bit.
198 *
199 * Atomically clear bit number @a bit of @a target and return its old value.
200 * The target may be a single atomic variable or an array of them.
201 *
202 * @param target Address of atomic variable or array.
203 * @param bit Bit number (starting from 0).
204 *
205 * @return 1 if the bit was set, 0 if it wasn't.
206 */
bt_mesh_atomic_test_and_clear_bit(bt_mesh_atomic_t * target,int bit)207 static inline int bt_mesh_atomic_test_and_clear_bit(bt_mesh_atomic_t *target, int bit)
208 {
209 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
210 bt_mesh_atomic_val_t old;
211
212 old = bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
213
214 return (old & mask) != 0;
215 }
216
217 /**
218 * @brief Atomically set a bit.
219 *
220 * Atomically set bit number @a bit of @a target and return its old value.
221 * The target may be a single atomic variable or an array of them.
222 *
223 * @param target Address of atomic variable or array.
224 * @param bit Bit number (starting from 0).
225 *
226 * @return 1 if the bit was set, 0 if it wasn't.
227 */
bt_mesh_atomic_test_and_set_bit(bt_mesh_atomic_t * target,int bit)228 static inline int bt_mesh_atomic_test_and_set_bit(bt_mesh_atomic_t *target, int bit)
229 {
230 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
231 bt_mesh_atomic_val_t old;
232
233 old = bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
234
235 return (old & mask) != 0;
236 }
237
238 /**
239 * @brief Atomically clear a bit.
240 *
241 * Atomically clear bit number @a bit of @a target.
242 * The target may be a single atomic variable or an array of them.
243 *
244 * @param target Address of atomic variable or array.
245 * @param bit Bit number (starting from 0).
246 *
247 * @return N/A
248 */
bt_mesh_atomic_clear_bit(bt_mesh_atomic_t * target,int bit)249 static inline void bt_mesh_atomic_clear_bit(bt_mesh_atomic_t *target, int bit)
250 {
251 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
252
253 (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
254 }
255
256 /**
257 * @brief Atomically set a bit.
258 *
259 * Atomically set bit number @a bit of @a target.
260 * The target may be a single atomic variable or an array of them.
261 *
262 * @param target Address of atomic variable or array.
263 * @param bit Bit number (starting from 0).
264 *
265 * @return N/A
266 */
bt_mesh_atomic_set_bit(bt_mesh_atomic_t * target,int bit)267 static inline void bt_mesh_atomic_set_bit(bt_mesh_atomic_t *target, int bit)
268 {
269 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
270
271 (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
272 }
273
274 /**
275 * @brief Atomically set a bit to a given value.
276 *
277 * Atomically set bit number @a bit of @a target to value @a val.
278 * The target may be a single atomic variable or an array of them.
279 *
280 * @param target Address of atomic variable or array.
281 * @param bit Bit number (starting from 0).
282 * @param val true for 1, false for 0.
283 *
284 * @return N/A
285 */
bt_mesh_atomic_set_bit_to(bt_mesh_atomic_t * target,int bit,bool val)286 static inline void bt_mesh_atomic_set_bit_to(bt_mesh_atomic_t *target, int bit, bool val)
287 {
288 bt_mesh_atomic_val_t mask = BLE_MESH_ATOMIC_MASK(bit);
289
290 if (val) {
291 (void)bt_mesh_atomic_or(BLE_MESH_ATOMIC_ELEM(target, bit), mask);
292 } else {
293 (void)bt_mesh_atomic_and(BLE_MESH_ATOMIC_ELEM(target, bit), ~mask);
294 }
295 }
296
297 /**
298 * @}
299 */
300
301 #ifdef __cplusplus
302 }
303 #endif
304
305 #endif /* _BLE_MESH_ATOMIC_H_ */
306