mesh_atomic.h 8.0 KB

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