Branch data Line data Source code
1 : : /* 2 : : * Copyright (c) 1997-2015, Wind River Systems, Inc. 3 : : * Copyright (c) 2021 Intel Corporation 4 : : * 5 : : * SPDX-License-Identifier: Apache-2.0 6 : : */ 7 : : 8 : : #ifndef ZEPHYR_INCLUDE_SYS_ATOMIC_H_ 9 : : #define ZEPHYR_INCLUDE_SYS_ATOMIC_H_ 10 : : 11 : : #include <stdbool.h> 12 : : #include <toolchain.h> 13 : : #include <stddef.h> 14 : : 15 : : #include <zephyr/types.h> 16 : : #include <sys/util_macro.h> 17 : : 18 : : #ifdef __cplusplus 19 : : extern "C" { 20 : : #endif 21 : : 22 : : typedef long atomic_t; 23 : : typedef atomic_t atomic_val_t; 24 : : typedef void *atomic_ptr_t; 25 : : typedef atomic_ptr_t atomic_ptr_val_t; 26 : : 27 : : /* Low-level primitives come in several styles: */ 28 : : 29 : : #if defined(CONFIG_ATOMIC_OPERATIONS_C) 30 : : /* Generic-but-slow implementation based on kernel locking and syscalls */ 31 : : #include <sys/atomic_c.h> 32 : : #elif defined(CONFIG_ATOMIC_OPERATIONS_ARCH) 33 : : /* Some architectures need their own implementation */ 34 : : # ifdef CONFIG_XTENSA 35 : : /* Not all Xtensa toolchains support GCC-style atomic intrinsics */ 36 : : # include <arch/xtensa/atomic_xtensa.h> 37 : : # else 38 : : /* Other arch specific implementation */ 39 : : # include <sys/atomic_arch.h> 40 : : # endif /* CONFIG_XTENSA */ 41 : : #else 42 : : /* Default. See this file for the Doxygen reference: */ 43 : : #include <sys/atomic_builtin.h> 44 : : #endif 45 : : 46 : : /* Portable higher-level utilities: */ 47 : : 48 : : /** 49 : : * @defgroup atomic_apis Atomic Services APIs 50 : : * @ingroup kernel_apis 51 : : * @{ 52 : : */ 53 : : 54 : : /** 55 : : * @brief Initialize an atomic variable. 56 : : * 57 : : * This macro can be used to initialize an atomic variable. For example, 58 : : * @code atomic_t my_var = ATOMIC_INIT(75); @endcode 59 : : * 60 : : * @param i Value to assign to atomic variable. 61 : : */ 62 : : #define ATOMIC_INIT(i) (i) 63 : : 64 : : /** 65 : : * @brief Initialize an atomic pointer variable. 66 : : * 67 : : * This macro can be used to initialize an atomic pointer variable. For 68 : : * example, 69 : : * @code atomic_ptr_t my_ptr = ATOMIC_PTR_INIT(&data); @endcode 70 : : * 71 : : * @param p Pointer value to assign to atomic pointer variable. 72 : : */ 73 : : #define ATOMIC_PTR_INIT(p) (p) 74 : : 75 : : /** 76 : : * @cond INTERNAL_HIDDEN 77 : : */ 78 : : 79 : : #define ATOMIC_BITS (sizeof(atomic_val_t) * 8) 80 : : #define ATOMIC_MASK(bit) BIT((unsigned long)(bit) & (ATOMIC_BITS - 1U)) 81 : : #define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) 82 : : 83 : : /** 84 : : * INTERNAL_HIDDEN @endcond 85 : : */ 86 : : 87 : : /** 88 : : * @brief This macro computes the number of atomic variables necessary to 89 : : * represent a bitmap with @a num_bits. 90 : : * 91 : : * @param num_bits Number of bits. 92 : : */ 93 : : #define ATOMIC_BITMAP_SIZE(num_bits) (1 + ((num_bits) - 1) / ATOMIC_BITS) 94 : : 95 : : /** 96 : : * @brief Define an array of atomic variables. 97 : : * 98 : : * This macro defines an array of atomic variables containing at least 99 : : * @a num_bits bits. 100 : : * 101 : : * @note 102 : : * If used from file scope, the bits of the array are initialized to zero; 103 : : * if used from within a function, the bits are left uninitialized. 104 : : * 105 : : * @cond INTERNAL_HIDDEN 106 : : * @note 107 : : * This macro should be replicated in the PREDEFINED field of the documentation 108 : : * Doxyfile. 109 : : * @endcond 110 : : * 111 : : * @param name Name of array of atomic variables. 112 : : * @param num_bits Number of bits needed. 113 : : */ 114 : : #define ATOMIC_DEFINE(name, num_bits) \ 115 : : atomic_t name[ATOMIC_BITMAP_SIZE(num_bits)] 116 : : 117 : : /** 118 : : * @brief Atomically test a bit. 119 : : * 120 : : * This routine tests whether bit number @a bit of @a target is set or not. 121 : : * The target may be a single atomic variable or an array of them. 122 : : * 123 : : * @note As for all atomic APIs, includes a 124 : : * full/sequentially-consistent memory barrier (where applicable). 125 : : * 126 : : * @param target Address of atomic variable or array. 127 : : * @param bit Bit number (starting from 0). 128 : : * 129 : : * @return true if the bit was set, false if it wasn't. 130 : : */ 131 : 0 : static inline bool atomic_test_bit(const atomic_t *target, int bit) 132 : : { 133 : 0 : atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit)); 134 : : 135 : 0 : return (1 & (val >> (bit & (ATOMIC_BITS - 1)))) != 0; 136 : : } 137 : : 138 : : /** 139 : : * @brief Atomically test and clear a bit. 140 : : * 141 : : * Atomically clear bit number @a bit of @a target and return its old value. 142 : : * The target may be a single atomic variable or an array of them. 143 : : * 144 : : * @note As for all atomic APIs, includes a 145 : : * full/sequentially-consistent memory barrier (where applicable). 146 : : * 147 : : * @param target Address of atomic variable or array. 148 : : * @param bit Bit number (starting from 0). 149 : : * 150 : : * @return true if the bit was set, false if it wasn't. 151 : : */ 152 : 0 : static inline bool atomic_test_and_clear_bit(atomic_t *target, int bit) 153 : : { 154 : 0 : atomic_val_t mask = ATOMIC_MASK(bit); 155 : : atomic_val_t old; 156 : : 157 : 0 : old = atomic_and(ATOMIC_ELEM(target, bit), ~mask); 158 : : 159 : 0 : return (old & mask) != 0; 160 : : } 161 : : 162 : : /** 163 : : * @brief Atomically set a bit. 164 : : * 165 : : * Atomically set bit number @a bit of @a target and return its old value. 166 : : * The target may be a single atomic variable or an array of them. 167 : : * 168 : : * @note As for all atomic APIs, includes a 169 : : * full/sequentially-consistent memory barrier (where applicable). 170 : : * 171 : : * @param target Address of atomic variable or array. 172 : : * @param bit Bit number (starting from 0). 173 : : * 174 : : * @return true if the bit was set, false if it wasn't. 175 : : */ 176 : 0 : static inline bool atomic_test_and_set_bit(atomic_t *target, int bit) 177 : : { 178 : 0 : atomic_val_t mask = ATOMIC_MASK(bit); 179 : : atomic_val_t old; 180 : : 181 : 0 : old = atomic_or(ATOMIC_ELEM(target, bit), mask); 182 : : 183 : 0 : return (old & mask) != 0; 184 : : } 185 : : 186 : : /** 187 : : * @brief Atomically clear a bit. 188 : : * 189 : : * Atomically clear bit number @a bit of @a target. 190 : : * The target may be a single atomic variable or an array of them. 191 : : * 192 : : * @note As for all atomic APIs, includes a 193 : : * full/sequentially-consistent memory barrier (where applicable). 194 : : * 195 : : * @param target Address of atomic variable or array. 196 : : * @param bit Bit number (starting from 0). 197 : : */ 198 : 0 : static inline void atomic_clear_bit(atomic_t *target, int bit) 199 : : { 200 : 0 : atomic_val_t mask = ATOMIC_MASK(bit); 201 : : 202 : 0 : (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); 203 : 0 : } 204 : : 205 : : /** 206 : : * @brief Atomically set a bit. 207 : : * 208 : : * Atomically set bit number @a bit of @a target. 209 : : * The target may be a single atomic variable or an array of them. 210 : : * 211 : : * @note As for all atomic APIs, includes a 212 : : * full/sequentially-consistent memory barrier (where applicable). 213 : : * 214 : : * @param target Address of atomic variable or array. 215 : : * @param bit Bit number (starting from 0). 216 : : */ 217 : 0 : static inline void atomic_set_bit(atomic_t *target, int bit) 218 : : { 219 : 0 : atomic_val_t mask = ATOMIC_MASK(bit); 220 : : 221 : 0 : (void)atomic_or(ATOMIC_ELEM(target, bit), mask); 222 : 0 : } 223 : : 224 : : /** 225 : : * @brief Atomically set a bit to a given value. 226 : : * 227 : : * Atomically set bit number @a bit of @a target to value @a val. 228 : : * The target may be a single atomic variable or an array of them. 229 : : * 230 : : * @note As for all atomic APIs, includes a 231 : : * full/sequentially-consistent memory barrier (where applicable). 232 : : * 233 : : * @param target Address of atomic variable or array. 234 : : * @param bit Bit number (starting from 0). 235 : : * @param val true for 1, false for 0. 236 : : */ 237 : : static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val) 238 : : { 239 : : atomic_val_t mask = ATOMIC_MASK(bit); 240 : : 241 : : if (val) { 242 : : (void)atomic_or(ATOMIC_ELEM(target, bit), mask); 243 : : } else { 244 : : (void)atomic_and(ATOMIC_ELEM(target, bit), ~mask); 245 : : } 246 : : } 247 : : 248 : : /** 249 : : * @} 250 : : */ 251 : : 252 : : #ifdef __cplusplus 253 : : } /* extern "C" */ 254 : : #endif 255 : : 256 : : #endif /* ZEPHYR_INCLUDE_SYS_ATOMIC_H_ */