1 /* 2 * Copyright (c) 2021 Intel Corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_INCLUDE_SYS_BITARRAY_H_ 8 #define ZEPHYR_INCLUDE_SYS_BITARRAY_H_ 9 10 #ifdef __cplusplus 11 extern "C" { 12 #endif 13 14 #include <stddef.h> 15 #include <stdint.h> 16 17 #include <zephyr/kernel.h> 18 #include <zephyr/sys/util.h> 19 20 /** 21 * @file 22 * 23 * @defgroup bitarray_apis Bit array 24 * @ingroup datastructure_apis 25 * 26 * @brief Store and manipulate bits in a bit array. 27 * 28 * @{ 29 */ 30 31 /** @cond INTERNAL_HIDDEN */ 32 struct sys_bitarray { 33 /* Number of bits */ 34 uint32_t num_bits; 35 36 /* Number of bundles */ 37 uint32_t num_bundles; 38 39 /* Bundle of bits */ 40 uint32_t *bundles; 41 42 /* Spinlock guarding access to this bit array */ 43 struct k_spinlock lock; 44 }; 45 /** @endcond */ 46 47 /** Bitarray structure */ 48 typedef struct sys_bitarray sys_bitarray_t; 49 50 /** 51 * @brief Create a bitarray object. 52 * 53 * @param name Name of the bitarray object. 54 * @param total_bits Total number of bits in this bitarray object. 55 * @param sba_mod Modifier to the bitarray variables. 56 */ 57 #define _SYS_BITARRAY_DEFINE(name, total_bits, sba_mod) \ 58 sba_mod uint32_t _sys_bitarray_bundles_##name \ 59 [DIV_ROUND_UP(DIV_ROUND_UP(total_bits, 8), \ 60 sizeof(uint32_t))] = {0}; \ 61 sba_mod sys_bitarray_t name = { \ 62 .num_bits = (total_bits), \ 63 .num_bundles = DIV_ROUND_UP( \ 64 DIV_ROUND_UP(total_bits, 8), sizeof(uint32_t)), \ 65 .bundles = _sys_bitarray_bundles_##name, \ 66 } 67 68 /** 69 * @brief Create a bitarray object. 70 * 71 * @param name Name of the bitarray object. 72 * @param total_bits Total number of bits in this bitarray object. 73 */ 74 #define SYS_BITARRAY_DEFINE(name, total_bits) \ 75 _SYS_BITARRAY_DEFINE(name, total_bits,) 76 77 /** 78 * @brief Create a static bitarray object. 79 * 80 * @param name Name of the bitarray object. 81 * @param total_bits Total number of bits in this bitarray object. 82 */ 83 #define SYS_BITARRAY_DEFINE_STATIC(name, total_bits) \ 84 _SYS_BITARRAY_DEFINE(name, total_bits, static) 85 86 /** 87 * Set a bit in a bit array 88 * 89 * @param[in] bitarray Bitarray struct 90 * @param[in] bit The bit to be set 91 * 92 * @retval 0 Operation successful 93 * @retval -EINVAL Invalid argument (e.g. bit to set exceeds 94 * the number of bits in bit array, etc.) 95 */ 96 int sys_bitarray_set_bit(sys_bitarray_t *bitarray, size_t bit); 97 98 /** 99 * Clear a bit in a bit array 100 * 101 * @param[in] bitarray Bitarray struct 102 * @param[in] bit The bit to be cleared 103 * 104 * @retval 0 Operation successful 105 * @retval -EINVAL Invalid argument (e.g. bit to clear exceeds 106 * the number of bits in bit array, etc.) 107 */ 108 int sys_bitarray_clear_bit(sys_bitarray_t *bitarray, size_t bit); 109 110 /** 111 * Test whether a bit is set or not 112 * 113 * @param[in] bitarray Bitarray struct 114 * @param[in] bit The bit to be tested 115 * @param[out] val The value of the bit (0 or 1) 116 * 117 * @retval 0 Operation successful 118 * @retval -EINVAL Invalid argument (e.g. bit to test exceeds 119 * the number of bits in bit array, etc.) 120 */ 121 int sys_bitarray_test_bit(sys_bitarray_t *bitarray, size_t bit, int *val); 122 123 /** 124 * Test the bit and set it 125 * 126 * @param[in] bitarray Bitarray struct 127 * @param[in] bit The bit to be tested and set 128 * @param[out] prev_val Previous value of the bit (0 or 1) 129 * 130 * @retval 0 Operation successful 131 * @retval -EINVAL Invalid argument (e.g. bit to test exceeds 132 * the number of bits in bit array, etc.) 133 */ 134 int sys_bitarray_test_and_set_bit(sys_bitarray_t *bitarray, size_t bit, int *prev_val); 135 136 /** 137 * Test the bit and clear it 138 * 139 * @param[in] bitarray Bitarray struct 140 * @param[in] bit The bit to be tested and cleared 141 * @param[out] prev_val Previous value of the bit (0 or 1) 142 * 143 * @retval 0 Operation successful 144 * @retval -EINVAL Invalid argument (e.g. bit to test exceeds 145 * the number of bits in bit array, etc.) 146 */ 147 int sys_bitarray_test_and_clear_bit(sys_bitarray_t *bitarray, size_t bit, int *prev_val); 148 149 /** 150 * Allocate bits in a bit array 151 * 152 * This finds a number of bits (@p num_bits) in a contiguous of 153 * previously unallocated region. If such a region exists, the bits are 154 * marked as allocated and the offset to the start of this region is 155 * returned via @p offset. 156 * 157 * @param[in] bitarray Bitarray struct 158 * @param[in] num_bits Number of bits to allocate 159 * @param[out] offset Offset to the start of allocated region if 160 * successful 161 * 162 * @retval 0 Allocation successful 163 * @retval -EINVAL Invalid argument (e.g. allocating more bits than 164 * the bitarray has, trying to allocate 0 bits, etc.) 165 * @retval -ENOSPC No contiguous region big enough to accommodate 166 * the allocation 167 */ 168 int sys_bitarray_alloc(sys_bitarray_t *bitarray, size_t num_bits, 169 size_t *offset); 170 171 /** 172 * Calculates the bit-wise XOR of two bitarrays in a region. 173 * The result is stored in the first bitarray passed in (@p dst). 174 * Both bitarrays must be of the same size. 175 * 176 * @param dst Bitarray struct 177 * @param other Bitarray struct 178 * @param num_bits Number of bits in the region, must be larger than 0 179 * @param offset Starting bit location 180 * 181 * @retval 0 Operation successful 182 * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, mismatching bitarrays, trying to xor 183 * 0 bits, etc.) 184 */ 185 int sys_bitarray_xor(sys_bitarray_t *dst, sys_bitarray_t *other, size_t num_bits, size_t offset); 186 187 /** 188 * Find nth bit set in region 189 * 190 * This counts the number of bits set (@p count) in a 191 * region (@p offset, @p num_bits) and returns the index (@p found_at) 192 * of the nth set bit, if it exists, as long with a zero return value. 193 * 194 * If it does not exist, @p found_at is not updated and the method returns 195 * 196 * @param[in] bitarray Bitarray struct 197 * @param[in] n Nth bit set to look for 198 * @param[in] num_bits Number of bits to check, must be larger than 0 199 * @param[in] offset Starting bit position 200 * @param[out] found_at Index of the nth bit set, if found 201 * 202 * @retval 0 Operation successful 203 * @retval 1 Nth bit set was not found in region 204 * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, trying to count 0 bits, etc.) 205 */ 206 int sys_bitarray_find_nth_set(sys_bitarray_t *bitarray, size_t n, size_t num_bits, size_t offset, 207 size_t *found_at); 208 209 /** 210 * Count bits set in a bit array region 211 * 212 * This counts the number of bits set (@p count) in a 213 * region (@p offset, @p num_bits). 214 * 215 * @param[in] bitarray Bitarray struct 216 * @param[in] num_bits Number of bits to check, must be larger than 0 217 * @param[in] offset Starting bit position 218 * @param[out] count Number of bits set in the region if successful 219 * 220 * @retval 0 Operation successful 221 * @retval -EINVAL Invalid argument (e.g. out-of-bounds access, trying to count 0 bits, etc.) 222 */ 223 int sys_bitarray_popcount_region(sys_bitarray_t *bitarray, size_t num_bits, size_t offset, 224 size_t *count); 225 226 /** 227 * Free bits in a bit array 228 * 229 * This marks the number of bits (@p num_bits) starting from @p offset 230 * as no longer allocated. 231 * 232 * @param bitarray Bitarray struct 233 * @param num_bits Number of bits to free 234 * @param offset Starting bit position to free 235 * 236 * @retval 0 Free is successful 237 * @retval -EINVAL Invalid argument (e.g. try to free more bits than 238 * the bitarray has, trying to free 0 bits, etc.) 239 * @retval -EFAULT The bits in the indicated region are not all allocated. 240 */ 241 int sys_bitarray_free(sys_bitarray_t *bitarray, size_t num_bits, 242 size_t offset); 243 244 /** 245 * Test if bits in a region is all set. 246 * 247 * This tests if the number of bits (@p num_bits) in region starting 248 * from @p offset are all set. 249 * 250 * @param bitarray Bitarray struct 251 * @param num_bits Number of bits to test 252 * @param offset Starting bit position to test 253 * 254 * @retval true All bits are set. 255 * @retval false Not all bits are set. 256 */ 257 bool sys_bitarray_is_region_set(sys_bitarray_t *bitarray, size_t num_bits, 258 size_t offset); 259 260 /** 261 * Test if bits in a region is all cleared. 262 * 263 * This tests if the number of bits (@p num_bits) in region starting 264 * from @p offset are all cleared. 265 * 266 * @param bitarray Bitarray struct 267 * @param num_bits Number of bits to test 268 * @param offset Starting bit position to test 269 * 270 * @retval true All bits are cleared. 271 * @retval false Not all bits are cleared. 272 */ 273 bool sys_bitarray_is_region_cleared(sys_bitarray_t *bitarray, size_t num_bits, 274 size_t offset); 275 276 /** 277 * Set all bits in a region. 278 * 279 * This sets the number of bits (@p num_bits) in region starting 280 * from @p offset. 281 * 282 * @param bitarray Bitarray struct 283 * @param num_bits Number of bits to test 284 * @param offset Starting bit position to test 285 * 286 * @retval 0 Operation successful 287 * @retval -EINVAL Invalid argument (e.g. bit to set exceeds 288 * the number of bits in bit array, etc.) 289 */ 290 int sys_bitarray_set_region(sys_bitarray_t *bitarray, size_t num_bits, 291 size_t offset); 292 293 /** 294 * Test if all bits in a region are cleared/set and set/clear them 295 * in a single atomic operation 296 * 297 * This checks if all the bits (@p num_bits) in region starting 298 * from @p offset are in required state. If even one bit is not, 299 * -EEXIST is returned. If the whole region is set/cleared 300 * it is set to opposite state. The check and set is performed as a single 301 * atomic operation. 302 * 303 * @param bitarray Bitarray struct 304 * @param num_bits Number of bits to test and set 305 * @param offset Starting bit position to test and set 306 * @param to_set if true the region will be set if all bits are cleared 307 * if false the region will be cleard if all bits are set 308 * 309 * @retval 0 Operation successful 310 * @retval -EINVAL Invalid argument (e.g. bit to set exceeds 311 * the number of bits in bit array, etc.) 312 * @retval -EEXIST at least one bit in the region is set/cleared, 313 * operation cancelled 314 */ 315 int sys_bitarray_test_and_set_region(sys_bitarray_t *bitarray, size_t num_bits, 316 size_t offset, bool to_set); 317 318 /** 319 * Clear all bits in a region. 320 * 321 * This clears the number of bits (@p num_bits) in region starting 322 * from @p offset. 323 * 324 * @param bitarray Bitarray struct 325 * @param num_bits Number of bits to test 326 * @param offset Starting bit position to test 327 * 328 * @retval 0 Operation successful 329 * @retval -EINVAL Invalid argument (e.g. bit to set exceeds 330 * the number of bits in bit array, etc.) 331 */ 332 int sys_bitarray_clear_region(sys_bitarray_t *bitarray, size_t num_bits, 333 size_t offset); 334 335 /** 336 * @} 337 */ 338 339 #ifdef __cplusplus 340 } 341 #endif 342 343 #endif /* ZEPHYR_INCLUDE_SYS_BITARRAY_H_ */ 344