From c6450c702dcb8dd24d89690e1d862a7983d0a256 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Mon, 8 Dec 2025 15:10:04 +0100 Subject: [PATCH 1/3] makefiles: add `$(call max_number, )` shell function This can be used to get the highest value out of a list of numeric numbers in a Makefile variable separated by whitespace. --- makefiles/utils/strings.mk | 5 +++++ makefiles/utils/test-strings.mk | 8 ++++++++ tests/build_system/utils/Makefile | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/makefiles/utils/strings.mk b/makefiles/utils/strings.mk index cbc280fcf005..c25e544da8fc 100644 --- a/makefiles/utils/strings.mk +++ b/makefiles/utils/strings.mk @@ -46,3 +46,8 @@ _is_equal = $(if $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))),1,) version_is_greater_or_equal = $(or \ $(call _is_greater,$(call _padded_version,$1),$(call _padded_version,$2)),\ $(call _is_equal,$(call _padded_version,$1),$(call _padded_version,$2))) + +# Get the maximum number of the natural numbers given as $1 +# $1: A list of natural numbers separated by white space +# Return: The value of the highest natural number in $1 +max_number = $(shell echo $1 | awk 'BEGIN{max=0} {for(i=1;i<=NF;i++){x=$$i; if (x > max){max = x}}} END{print max}') diff --git a/makefiles/utils/test-strings.mk b/makefiles/utils/test-strings.mk index 56e48c60692e..9ca6b7cca544 100644 --- a/makefiles/utils/test-strings.mk +++ b/makefiles/utils/test-strings.mk @@ -35,3 +35,11 @@ test-version_is_greater_or_equal: $(Q)test 1 = "$(call version_is_greater_or_equal,$(TEST_VERSION_4),$(TEST_VERSION_3))" || { echo ERROR: "$(TEST_VERSION_3)" \< "$(TEST_VERSION_4)"; exit 1; } $(Q)test "" = "$(call version_is_greater_or_equal,$(TEST_VERSION_3),$(TEST_VERSION_4))" || { echo ERROR: Test should fail, "$(TEST_VERSION_4)" is not \< "$(TEST_VERSION_3)"; exit 1; } $(Q)test "" = "$(call version_is_greater_or_equal,$(TEST_VERSION_1),$(TEST_VERSION_4))" || { echo ERROR: Test should fail, "$(TEST_VERSION_1)" is not \< "$(TEST_VERSION_4)"; exit 1; } + +test-max_number: + $(Q)test "8" = "$(call max_number, 7 4 8 0 1 3)" + $(Q)test "42" = "$(call max_number, 42 4 8 0 1 3)" + $(Q)test "1337" = "$(call max_number, 42 4 8 0 1 1337)" + $(Q)test "0" = "$(call max_number, 0 0 0 0 0)" + $(Q)test "13" = "$(call max_number, 13)" + $(Q)test "0" = "$(call max_number,)" diff --git a/tests/build_system/utils/Makefile b/tests/build_system/utils/Makefile index fad162b0e76d..e376f0a641a6 100644 --- a/tests/build_system/utils/Makefile +++ b/tests/build_system/utils/Makefile @@ -24,6 +24,7 @@ COMPILE_TESTS += test-uppercase COMPILE_TESTS += test-uppercase_and_underscore COMPILE_TESTS += test-version_is_greater COMPILE_TESTS += test-version_is_greater_or_equal +COMPILE_TESTS += test-max_number # Tests will be run both in the host machine and in `docker` all: build-system-utils-tests @@ -59,3 +60,6 @@ test-version_is_greater: test-version_is_greater_or_equal: $(Q)$(call command_should_succeed,"$(MAKE)" -C $(MAKEFILES_UTILS) -f test-strings.mk test-version_is_greater_or_equal) + +test-max_number: + $(Q)$(call command_should_succeed,"$(MAKE)" -C $(MAKEFILES_UTILS) -f test-strings.mk test-max_number) From f0540a90007a8b3e466fa76ca3658e8a6875146f Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Mon, 8 Dec 2025 15:47:59 +0100 Subject: [PATCH 2/3] sys/event: manage event thread size via build system This adds a mechanism for modules to declare requirements on the thread stack size in their `Makefile.dep` and let the build system then override the default stack size, if any requirements are declared. The motivation is to allow multiple modules to have special requirements without causing conflicts, as just adding the following to their `Makefile.include` would do: ```Makefile CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE= ``` Instead, the new mechanism would work by having them both declare in their `Makefile.dep`: ```Makefile EVENT_THREAD_MEDIUM_STACKSIZE_MIN += ``` The build system then picks the maximum number in `EVENT_THREAD_MEDIUM_STACKSIZE_MIN` and exposes this as stack size, if any module did declare a minimum requirement. Co-authored-by: benpicco --- sys/Makefile.include | 4 ++++ sys/event/Makefile.include | 35 +++++++++++++++++++++++++++++++++++ sys/include/event/thread.h | 26 ++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 sys/event/Makefile.include diff --git a/sys/Makefile.include b/sys/Makefile.include index 280e0851db68..80d51b4f12df 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -212,3 +212,7 @@ endif ifneq (,$(filter unicoap,$(USEMODULE))) include $(RIOTBASE)/sys/net/application_layer/unicoap/Makefile.include endif + +ifneq (,$(filter event,$(USEMODULE))) + include $(RIOTBASE)/sys/event/Makefile.include +endif diff --git a/sys/event/Makefile.include b/sys/event/Makefile.include new file mode 100644 index 000000000000..c986438e5ab2 --- /dev/null +++ b/sys/event/Makefile.include @@ -0,0 +1,35 @@ +include $(RIOTMAKE)/utils/strings.mk + +# This applies to all thread stacks +ifneq (, $(EVENT_THREAD_STACKSIZE_MIN)) + EVENT_THREAD_STACKSIZE_MIN := $(call max_number,$(EVENT_THREAD_STACKSIZE_MIN)) +endif + +ifeq (,$(filter event_thread_highest, $(USEMODULE))) + # No highest priority event thread, so the highest prio queue is handled by + # the same thread handling the medium priority queue. So we "trickle down" + # the requirements here + EVENT_THREAD_MEDIUM_STACKSIZE_MIN += $(EVENT_THREAD_HIGHEST_STACKSIZE_MIN) +else + ifneq (, $(EVENT_THREAD_HIGHEST_STACKSIZE_MIN)) + EVENT_THREAD_HIGHEST_STACKSIZE_MIN := $(call max_number,$(EVENT_THREAD_HIGHEST_STACKSIZE_MIN) $(EVENT_THREAD_STACKSIZE_MIN)) + CFLAGS += -DEVENT_THREAD_HIGHEST_STACKSIZE=$(EVENT_THREAD_HIGHEST_STACKSIZE_MIN) + endif +endif + +ifeq (,$(filter event_thread_medium, $(USEMODULE))) + # No medium priority event thread, so the medium prio queue is handled by + # the same thread handling the lowest priority queue. So we "trickle down" + # the requirements here + EVENT_THREAD_LOWEST_STACKSIZE_MIN += $(EVENT_THREAD_MEDIUM_STACKSIZE_MIN) +else + ifneq (, $(EVENT_THREAD_MEDIUM_STACKSIZE_MIN)) + EVENT_THREAD_MEDIUM_STACKSIZE_MIN := $(call max_number,$(EVENT_THREAD_MEDIUM_STACKSIZE_MIN) $(EVENT_THREAD_STACKSIZE_MIN)) + CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE=$(EVENT_THREAD_MEDIUM_STACKSIZE_MIN) + endif +endif + +ifneq (, $(EVENT_THREAD_LOWEST_STACKSIZE_MIN)) + EVENT_THREAD_LOWEST_STACKSIZE_MIN := $(call max_number,$(EVENT_THREAD_LOWEST_STACKSIZE_MIN) $(EVENT_THREAD_STACKSIZE_MIN)) + CFLAGS += -DEVENT_THREAD_LOWEST_STACKSIZE=$(EVENT_THREAD_LOWEST_STACKSIZE_MIN) +endif diff --git a/sys/include/event/thread.h b/sys/include/event/thread.h index 1e277bee4089..f76c0852aadc 100644 --- a/sys/include/event/thread.h +++ b/sys/include/event/thread.h @@ -44,6 +44,32 @@ * event queue gets its own thread. So higher priority events will always * preempt events of lower priority in this case. * + * Managing Stack Size Requirements + * -------------------------------- + * + * A module using the medium priority event queue might require a certain + * minimum stack size, say 1024, to operate correctly. Instead of just adding + * `CFLAGS += -DDEVENT_THREAD_MEDIUM_STACKSIZE=1024`, it can instead add the + * following to its `Makefile.dep`: + * + * ```Makefile + * EVENT_THREAD_MEDIUM_STACKSIZE_MIN += 1024 + * ``` + * + * In the `Makefile.include` of `sys/event` the highest value of the minimum + * requirements declared by any module will be picked and added to the + * `CFLAGS`. + * + * @note `EVENT_THREAD_MEDIUM_STACKSIZE_MIN` and + * `EVENT_THREAD_HIGHEST_STACKSIZE_MIN` always apply to the thread + * managing the medium priority queue. + * @details E.g. without the module `event_thread_medium` the lowest priority + * and medium priority queues are both handled by the lowest priority + * even thread. In that case, `EVENT_THREAD_MEDIUM_STACKSIZE_MIN` would + * ensure a minimum thread statck size on the lowest priority even + * thread. With `event_thread_medium` in use, it would instead apply + * to the stack of the dedicated medium event queue thread. + * * @{ * * @file From 37eb21325fc7d70f976db649b8cb5dc0d4b37137 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Mon, 8 Dec 2025 15:53:04 +0100 Subject: [PATCH 3/3] tests/sys/event_thread_shared: test stack size handling This adds a simple integration test for declaring the stack size requirements in modules. --- makefiles/app_dirs.blacklist | 1 + tests/sys/event_thread_shared/Makefile | 8 ++++++++ .../external_modules/test_module_a/Makefile | 1 + .../external_modules/test_module_a/Makefile.dep | 1 + .../external_modules/test_module_b/Makefile | 1 + .../external_modules/test_module_b/Makefile.dep | 1 + .../external_modules/test_module_c/Makefile | 1 + .../external_modules/test_module_c/Makefile.dep | 1 + .../external_modules/test_module_d/Makefile | 1 + .../external_modules/test_module_d/Makefile.dep | 1 + tests/sys/event_thread_shared/main.c | 6 ++++++ 11 files changed, 23 insertions(+) create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_a/Makefile create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_a/Makefile.dep create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_b/Makefile create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_b/Makefile.dep create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_c/Makefile create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_c/Makefile.dep create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_d/Makefile create mode 100644 tests/sys/event_thread_shared/external_modules/test_module_d/Makefile.dep diff --git a/makefiles/app_dirs.blacklist b/makefiles/app_dirs.blacklist index b5b1d30e212e..99a6270cb4c2 100644 --- a/makefiles/app_dirs.blacklist +++ b/makefiles/app_dirs.blacklist @@ -20,4 +20,5 @@ tests/pkg/tflite-micro/external_modules/ tests/pkg/utensor/external_modules/ tests/pkg/wolfcrypt-ed25519-verify/ tests/sys/suit_manifest/native_flashpage/ +tests/sys/event_thread_shared/external_modules/ tests/unittests/ diff --git a/tests/sys/event_thread_shared/Makefile b/tests/sys/event_thread_shared/Makefile index 39c389aa57b4..b7774b59a175 100644 --- a/tests/sys/event_thread_shared/Makefile +++ b/tests/sys/event_thread_shared/Makefile @@ -2,4 +2,12 @@ include ../Makefile.sys_common USEMODULE += event_thread +# Test that selecting event thread size works from the modules `Makefile.dep` +# work as expected by including a bunch of empty test module +EXTERNAL_MODULE_DIRS += external_modules +USEMODULE += test_module_a +USEMODULE += test_module_b +USEMODULE += test_module_c +USEMODULE += test_module_d + include $(RIOTBASE)/Makefile.include diff --git a/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile b/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile.dep b/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile.dep new file mode 100644 index 000000000000..f83f3a04cd74 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_a/Makefile.dep @@ -0,0 +1 @@ +EVENT_THREAD_HIGHEST_STACKSIZE_MIN += 3 diff --git a/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile b/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile.dep b/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile.dep new file mode 100644 index 000000000000..145df9317779 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_b/Makefile.dep @@ -0,0 +1 @@ +EVENT_THREAD_HIGHEST_STACKSIZE_MIN += 300 diff --git a/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile b/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile.dep b/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile.dep new file mode 100644 index 000000000000..82ff829e45a5 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_c/Makefile.dep @@ -0,0 +1 @@ +EVENT_THREAD_HIGHEST_STACKSIZE_MIN += 567 diff --git a/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile b/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile.dep b/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile.dep new file mode 100644 index 000000000000..015b5fd83305 --- /dev/null +++ b/tests/sys/event_thread_shared/external_modules/test_module_d/Makefile.dep @@ -0,0 +1 @@ +EVENT_THREAD_HIGHEST_STACKSIZE_MIN += 256 diff --git a/tests/sys/event_thread_shared/main.c b/tests/sys/event_thread_shared/main.c index 5945bbfce15e..c187da847be4 100644 --- a/tests/sys/event_thread_shared/main.c +++ b/tests/sys/event_thread_shared/main.c @@ -17,11 +17,17 @@ * @} */ +#include #include #include "thread.h" #include "event/thread.h" +static_assert(EVENT_THREAD_LOWEST_STACKSIZE == 567, + "Selecting highest of the minimum stack size requirements " + "declared via `EVENT_THREAD_HIGHEST_STACKSIZE_MIN += ` " + "must work correctly"); + static void _handler_high(event_t *event) { (void)event; puts("high");