lib: bitarray: sys_bitarray_test_and_set_region added
a method to check and set/clear a chosen region in a bitmap
if not previously set/cleared in a single atomic operation.
Useful for keeping track of resources usage, like memory banks
Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
diff --git a/include/sys/bitarray.h b/include/sys/bitarray.h
index 792e26c..e407a36 100644
--- a/include/sys/bitarray.h
+++ b/include/sys/bitarray.h
@@ -228,6 +228,31 @@
size_t offset);
/**
+ * Test if all bits in a region are cleared/set and set/clear them
+ * in a single atomic operation
+ *
+ * This checks if all the bits (@p num_bits) in region starting
+ * from @p offset are in required state. If even one bit is not,
+ * -EEXIST is returned. If the whole region is set/cleared
+ * it is set to opposite state. The check and set is performed as a single
+ * atomic operation.
+ *
+ * @param bitarray Bitarray struct
+ * @param num_bits Number of bits to test and set
+ * @param offset Starting bit position to test and set
+ * @param to_set if true the region will be set if all bits are cleared
+ * if false the region will be cleard if all bits are set
+ *
+ * @retval 0 Operation successful
+ * @retval -EINVAL Invalid argument (e.g. bit to set exceeds
+ * the number of bits in bit array, etc.)
+ * @retval -EEXIST at least one bit in the region is set/cleared,
+ * operation cancelled
+ */
+int sys_bitarray_test_and_set_region(sys_bitarray_t *bitarray, size_t num_bits,
+ size_t offset, bool to_set);
+
+/**
* Clear all bits in a region.
*
* This clears the number of bits (@p num_bits) in region starting
diff --git a/lib/os/bitarray.c b/lib/os/bitarray.c
index f40739e..e63c3b4 100644
--- a/lib/os/bitarray.c
+++ b/lib/os/bitarray.c
@@ -547,6 +547,39 @@
return ret;
}
+int sys_bitarray_test_and_set_region(sys_bitarray_t *bitarray, size_t num_bits,
+ size_t offset, bool to_set)
+{
+ int ret;
+ bool region_clear;
+ struct bundle_data bd;
+
+ size_t off_end = offset + num_bits - 1;
+ k_spinlock_key_t key = k_spin_lock(&bitarray->lock);
+
+ __ASSERT_NO_MSG(bitarray->num_bits > 0);
+
+ if ((num_bits == 0)
+ || (num_bits > bitarray->num_bits)
+ || (offset >= bitarray->num_bits)
+ || (off_end >= bitarray->num_bits)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ region_clear = match_region(bitarray, offset, num_bits, !to_set, &bd, NULL);
+ if (region_clear) {
+ set_region(bitarray, offset, num_bits, to_set, &bd);
+ ret = 0;
+ } else {
+ ret = -EEXIST;
+ }
+
+out:
+ k_spin_unlock(&bitarray->lock, key);
+ return ret;
+}
+
int sys_bitarray_set_region(sys_bitarray_t *bitarray, size_t num_bits,
size_t offset)
{