From 0f3d37ae48f9c948550a51fe88722f4ec83de404 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Wed, 11 Feb 2026 19:01:20 +0100 Subject: [PATCH 1/4] Feature: Bitmap algorithms Add algorithm templates to work with bitmap fields. These algorithms support arbitrary length of bitmap field. Following operations are supported: - setting bit in field - clearing bit in field - testing bit in field - finding first available bit in field No tests yet. --- src/os/kernel/algo.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/os/kernel/algo.h b/src/os/kernel/algo.h index 85fb0b1f..c57970bb 100644 --- a/src/os/kernel/algo.h +++ b/src/os/kernel/algo.h @@ -227,3 +227,22 @@ inline uint32_t os_hash_key(uint32_t key) }\ pos;\ }) + +#define BITMAP_SET(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] |= (1U << ((_POS) & 31)); +#define BITMAP_CLEAR(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] &= ~(1U << ((_POS) & 31)); +#define BITMAP_TEST(_BITMAP, _POS, _SIZE) return (_BITMAP[(_POS) >> 5] & (1U << ((_POS) & 31))) != 0; +#define BITMAP_FIRST(_BITMAP, _SIZE) \ +({\ + uint32_t first = ~0;\ + for (int word = 0; word < _SIZE; ++word) {\ + uint32_t ready = _BITMAP[word];\ + if (ready) {\ + uint8_t bit = __builtin_ctz(ready);\ + first = (word << 5) + bit;\ + break;\ + }\ + }\ + first;\ +}) +#define BITMAP_COPY(_TARGET, _SOURCE, _SIZE) \ + for (unsigned q = 0; q < _SIZE; ++q) _TARGET[q] = _SOURCE[q]; From f20b28a4e6be91e19d7fbea18fb7d8fa361f7034 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Tue, 24 Feb 2026 15:30:45 +0100 Subject: [PATCH 2/4] Feature: Make algo library publicly available Move algo library to where it is publicly accessible and can be included from ordinary application software. This way it can use algorithms in here. If they are good enough for kernel, they could be working for application software as well. --- {src/os/kernel => include/cmrx}/algo.h | 2 +- src/os/kernel/algo.c | 2 +- src/os/kernel/notify.c | 2 +- src/os/kernel/tests/algo_binary_search.c | 2 +- src/os/kernel/tests/algo_data.c | 2 +- src/os/kernel/tests/algo_hash_search.c | 2 +- src/os/kernel/tests/algo_insert_sort.c | 2 +- src/os/kernel/tests/os_setitimer.c | 2 +- src/os/kernel/timer.c | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) rename {src/os/kernel => include/cmrx}/algo.h (98%) diff --git a/src/os/kernel/algo.h b/include/cmrx/algo.h similarity index 98% rename from src/os/kernel/algo.h rename to include/cmrx/algo.h index c57970bb..2872b394 100644 --- a/src/os/kernel/algo.h +++ b/include/cmrx/algo.h @@ -230,7 +230,7 @@ inline uint32_t os_hash_key(uint32_t key) #define BITMAP_SET(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] |= (1U << ((_POS) & 31)); #define BITMAP_CLEAR(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] &= ~(1U << ((_POS) & 31)); -#define BITMAP_TEST(_BITMAP, _POS, _SIZE) return (_BITMAP[(_POS) >> 5] & (1U << ((_POS) & 31))) != 0; +#define BITMAP_TEST(_BITMAP, _POS, _SIZE) ((_BITMAP[(_POS) >> 5] & (1U << ((_POS) & 31))) != 0) #define BITMAP_FIRST(_BITMAP, _SIZE) \ ({\ uint32_t first = ~0;\ diff --git a/src/os/kernel/algo.c b/src/os/kernel/algo.c index 3d5b6dd6..5db6d2ea 100644 --- a/src/os/kernel/algo.c +++ b/src/os/kernel/algo.c @@ -1,3 +1,3 @@ -#include "algo.h" +#include uint32_t os_hash_key(uint32_t key); diff --git a/src/os/kernel/notify.c b/src/os/kernel/notify.c index 4b6aae52..b20cf242 100644 --- a/src/os/kernel/notify.c +++ b/src/os/kernel/notify.c @@ -8,7 +8,7 @@ #include #include #include -#include "algo.h" +#include static struct NotificationObject os_notification_buffer[OS_NOTIFICATION_BUFFER_SIZE]; unsigned os_notification_buffer_size; diff --git a/src/os/kernel/tests/algo_binary_search.c b/src/os/kernel/tests/algo_binary_search.c index 3c2093fe..4860830e 100644 --- a/src/os/kernel/tests/algo_binary_search.c +++ b/src/os/kernel/tests/algo_binary_search.c @@ -1,5 +1,5 @@ #include -#include +#include #include "algo_data.h" CTEST_DATA(algo_binary_search) { diff --git a/src/os/kernel/tests/algo_data.c b/src/os/kernel/tests/algo_data.c index bf73b7bf..5ae3e5b5 100644 --- a/src/os/kernel/tests/algo_data.c +++ b/src/os/kernel/tests/algo_data.c @@ -1,5 +1,5 @@ #include "algo_data.h" -#include +#include // To force hashing function emission uint32_t os_hash_key(uint32_t key); diff --git a/src/os/kernel/tests/algo_hash_search.c b/src/os/kernel/tests/algo_hash_search.c index 9d43f8f7..77bc1b58 100644 --- a/src/os/kernel/tests/algo_hash_search.c +++ b/src/os/kernel/tests/algo_hash_search.c @@ -1,5 +1,5 @@ #include -#include +#include #include "algo_data.h" void hash_insert(uint32_t key) diff --git a/src/os/kernel/tests/algo_insert_sort.c b/src/os/kernel/tests/algo_insert_sort.c index b8e00756..cb05bd3f 100644 --- a/src/os/kernel/tests/algo_insert_sort.c +++ b/src/os/kernel/tests/algo_insert_sort.c @@ -1,5 +1,5 @@ #include -#include +#include #include "algo_data.h" CTEST_DATA(algo_insert_sort) { diff --git a/src/os/kernel/tests/os_setitimer.c b/src/os/kernel/tests/os_setitimer.c index 25b6bc5f..c174c2fe 100644 --- a/src/os/kernel/tests/os_setitimer.c +++ b/src/os/kernel/tests/os_setitimer.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/src/os/kernel/timer.c b/src/os/kernel/timer.c index 153e1ba4..f5ef3a4d 100644 --- a/src/os/kernel/timer.c +++ b/src/os/kernel/timer.c @@ -6,7 +6,7 @@ #include "signal.h" #include "notify.h" #include "txn.h" -#include "algo.h" +#include #include #include From 2f5c0e5704d4c0a5bb7905e3a9968b4e6499d285 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Tue, 24 Feb 2026 15:59:52 +0100 Subject: [PATCH 3/4] Tests: Bitmap algorithm unit tests --- include/cmrx/algo.h | 2 +- src/os/kernel/tests/CMakeLists.txt | 1 + src/os/kernel/tests/algo_bitmap.c | 104 +++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/os/kernel/tests/algo_bitmap.c diff --git a/include/cmrx/algo.h b/include/cmrx/algo.h index 2872b394..2a596820 100644 --- a/include/cmrx/algo.h +++ b/include/cmrx/algo.h @@ -234,7 +234,7 @@ inline uint32_t os_hash_key(uint32_t key) #define BITMAP_FIRST(_BITMAP, _SIZE) \ ({\ uint32_t first = ~0;\ - for (int word = 0; word < _SIZE; ++word) {\ + for (unsigned word = 0; word < _SIZE; ++word) {\ uint32_t ready = _BITMAP[word];\ if (ready) {\ uint8_t bit = __builtin_ctz(ready);\ diff --git a/src/os/kernel/tests/CMakeLists.txt b/src/os/kernel/tests/CMakeLists.txt index 8d213df1..90bb709e 100644 --- a/src/os/kernel/tests/CMakeLists.txt +++ b/src/os/kernel/tests/CMakeLists.txt @@ -42,6 +42,7 @@ set(test_algo_SRCS algo_binary_search.c algo_insert_sort.c algo_hash_search.c + algo_bitmap.c ) add_executable(test_algo ${test_algo_SRCS}) diff --git a/src/os/kernel/tests/algo_bitmap.c b/src/os/kernel/tests/algo_bitmap.c new file mode 100644 index 00000000..e5912363 --- /dev/null +++ b/src/os/kernel/tests/algo_bitmap.c @@ -0,0 +1,104 @@ +#include +#include +#include "algo_data.h" + +#define BITMAP_SIZE 4 +#define BITMAP_MAX (BITMAP_SIZE * 8 * sizeof(uint32_t)) + +CTEST_DATA(algo_bitmap) { + uint32_t bitmap[BITMAP_SIZE]; +}; + +CTEST_SETUP(algo_bitmap) { + for (unsigned q = 0; q < BITMAP_SIZE; ++q) + { + data->bitmap[q] = 0; + } +} + +CTEST2(algo_bitmap, find_empty) { + uint32_t item = BITMAP_FIRST(data->bitmap, BITMAP_SIZE); + ASSERT_EQUAL(item, ~0U); +} + +CTEST2(algo_bitmap, set_one) { + BITMAP_SET(data->bitmap, 0, BITMAP_MAX); + bool is_set = BITMAP_TEST(data->bitmap, 0, BITMAP_SIZE); + ASSERT_TRUE(is_set); +} + +CTEST2(algo_bitmap, set_multiple) { + BITMAP_SET(data->bitmap, 0, BITMAP_MAX); + bool is_set = BITMAP_TEST(data->bitmap, 0, BITMAP_SIZE); + ASSERT_TRUE(is_set); + + BITMAP_SET(data->bitmap, 1, BITMAP_MAX); + is_set = BITMAP_TEST(data->bitmap, 1, BITMAP_SIZE); + ASSERT_TRUE(is_set); + + BITMAP_SET(data->bitmap, 2, BITMAP_MAX); + is_set = BITMAP_TEST(data->bitmap, 2, BITMAP_SIZE); + ASSERT_TRUE(is_set); +} + +/* Set last bit, check no previous was set */ +CTEST2(algo_bitmap, set_and_check_correct_item) { + BITMAP_SET(data->bitmap, BITMAP_MAX - 1, BITMAP_SIZE); + uint32_t item = BITMAP_FIRST(data->bitmap, BITMAP_SIZE); + ASSERT_EQUAL(item, BITMAP_MAX - 1); +} + +/* Set multiple bits at the end of list, check no previous were set and no set bit was cleared */ +CTEST2(algo_bitmap, set_multiple_check_correct) { + BITMAP_SET(data->bitmap, BITMAP_MAX - 1, BITMAP_SIZE); + + BITMAP_SET(data->bitmap, BITMAP_MAX - 2, BITMAP_SIZE); + + uint32_t item = BITMAP_FIRST(data->bitmap, BITMAP_SIZE); + ASSERT_EQUAL(item, BITMAP_MAX - 2); + bool is_set = BITMAP_TEST(data->bitmap, BITMAP_MAX - 1, BITMAP_SIZE); + ASSERT_TRUE(is_set); +} + +CTEST2(algo_bitmap, set_and_clear_one) { + BITMAP_SET(data->bitmap, 0, BITMAP_MAX); + BITMAP_CLEAR(data->bitmap, 0, BITMAP_MAX); + bool is_set = BITMAP_TEST(data->bitmap, 0, BITMAP_SIZE); + ASSERT_FALSE(is_set); +} + +CTEST2(algo_bitmap, set_and_clear_no_residues) { + BITMAP_SET(data->bitmap, 0, BITMAP_MAX); + BITMAP_CLEAR(data->bitmap, 0, BITMAP_MAX); + + uint32_t item = BITMAP_FIRST(data->bitmap, BITMAP_SIZE); + ASSERT_EQUAL(item, ~0U); +} + + +CTEST2(algo_bitmap, set_and_clear_correct) { + BITMAP_SET(data->bitmap, 0, BITMAP_MAX); + BITMAP_SET(data->bitmap, 1, BITMAP_MAX); + BITMAP_CLEAR(data->bitmap, 0, BITMAP_MAX); + bool is_set = BITMAP_TEST(data->bitmap, 0, BITMAP_SIZE); + ASSERT_FALSE(is_set); + + is_set = BITMAP_TEST(data->bitmap, 1, BITMAP_SIZE); + ASSERT_TRUE(is_set); +} + +CTEST2(algo_bitmap, set_copy_and_check) { + uint32_t my_bitmap[BITMAP_SIZE]; + + BITMAP_SET(data->bitmap, BITMAP_MAX - 1, BITMAP_SIZE); + + BITMAP_SET(data->bitmap, BITMAP_MAX - 2, BITMAP_SIZE); + + BITMAP_COPY(my_bitmap, data->bitmap, BITMAP_SIZE); + + uint32_t item = BITMAP_FIRST(my_bitmap, BITMAP_SIZE); + ASSERT_EQUAL(item, BITMAP_MAX - 2); + bool is_set = BITMAP_TEST(my_bitmap, BITMAP_MAX - 1, BITMAP_SIZE); + ASSERT_TRUE(is_set); + +} From f0418d66b7b5ebfe35dd8e2f5c6fb0eea6c750e6 Mon Sep 17 00:00:00 2001 From: Eduard Drusa Date: Tue, 24 Feb 2026 16:09:08 +0100 Subject: [PATCH 4/4] Docs: Document bitmap algorithms --- include/cmrx/algo.h | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/cmrx/algo.h b/include/cmrx/algo.h index 2a596820..9eb85154 100644 --- a/include/cmrx/algo.h +++ b/include/cmrx/algo.h @@ -1,6 +1,21 @@ #pragma once #include +/** @defgroup api_algo Algorithm templates + * @ingroup api + * Templates for algorithms to work with some common data types. Algorithms + * implemented here are "templates". They are provided as macros which adapt + * to underlying types. This means these algorithms can run faster as they + * are not generic, but it also means that each use will generate its own + * copy. + * + * Currently algorithms to work with arrays (insert, delete, binary search), + * hash tables (searching) and bitmaps (set, clear, test, find first) are + * implemented. Main user of these algorithms is kernel itself yet as they + * are optimized for embedded they are accessible to userspace programs + * as well. + * @{ + */ /** Binary search algorithm. * This is a template for binary searching over a sorted compacted array. @@ -174,6 +189,7 @@ inline uint32_t os_hash_key(uint32_t key) } #endif +/** Reserved value denoting that tash table key is empty */ #define HASH_EMPTY 0xFFFFFFFFU /** Find entry in hash table. @@ -228,9 +244,40 @@ inline uint32_t os_hash_key(uint32_t key) pos;\ }) +/** Template for setting bit in bitmap. + * Sets bit in bitmap of arbitrary size as if it was one continuous array of bits. + * + * @param _BITMAP bitmap identity + * @param _POS bit to be set + * @param _SIZE bitmap size + */ #define BITMAP_SET(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] |= (1U << ((_POS) & 31)); + +/** Template for clearing bit in bitmap. + * Clears bit in bitmap of arbitrary size as if it was one continuous array of bits. + * + * @param _BITMAP bitmap identity + * @param _POS bit to be set + * @param _SIZE bitmap size + */ #define BITMAP_CLEAR(_BITMAP, _POS, _SIZE) _BITMAP[(_POS) >> 5] &= ~(1U << ((_POS) & 31)); + +/** Template for testing if bit is set in bitmap. + * Tests if bit in bitmap of arbitrary size is set. + * + * @param _BITMAP bitmap identity + * @param _POS bit to be set + * @param _SIZE bitmap size + */ #define BITMAP_TEST(_BITMAP, _POS, _SIZE) ((_BITMAP[(_POS) >> 5] & (1U << ((_POS) & 31))) != 0) + +/** Return first set bit in the bitmap. + * Returns first bit set in bitmap of arbitrary size as if it was one continuous array of bits. + * + * @param _BITMAP bitmap identity + * @param _SIZE bitmap size + * @returns position of first bit counted from the beginning of bitmap, or ~0U if no bit is set. + */ #define BITMAP_FIRST(_BITMAP, _SIZE) \ ({\ uint32_t first = ~0;\ @@ -246,3 +293,6 @@ inline uint32_t os_hash_key(uint32_t key) }) #define BITMAP_COPY(_TARGET, _SOURCE, _SIZE) \ for (unsigned q = 0; q < _SIZE; ++q) _TARGET[q] = _SOURCE[q]; + + +/* }@ */