diff --git a/Makefile.dep b/Makefile.dep index 77c6528a67..65abf25c11 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -1074,6 +1074,9 @@ FEATURES_REQUIRED += $(filter arch_%,$(FEATURES_PROVIDED)) # always select CPU core features FEATURES_REQUIRED += $(filter cpu_core_%,$(FEATURES_PROVIDED)) +# don't use idle thread if architecture has needed support +FEATURES_OPTIONAL += no_idle_thread + ifneq (,$(filter ecc_%,$(USEMODULE))) USEMODULE += ecc endif diff --git a/core/include/sched.h b/core/include/sched.h index 5eb533443f..f37092cc46 100644 --- a/core/include/sched.h +++ b/core/include/sched.h @@ -203,8 +203,22 @@ extern clist_node_t sched_runqueues[SCHED_PRIO_LEVELS]; */ NORETURN void sched_task_exit(void); -#if IS_USED(MODULE_SCHED_CB) || defined(DOXYGEN) +/** + * @brief Set CPU to idle mode (CPU dependent) + * + * Only used when there's no idle thread. + * + * This function will be called by the scheduler when there's no runnable thread. + * It will be called from ISR context, and *must* allow other ISR handlers to be run. + * E.g., on Cortex-M, the PendSV priority is temporarily lowered (set to higher + * value) in order to enable other exceptions to be run. + * + * This function should also invoke setting a low power mode, e.g., by calling + * 'pm_set_lowest()'. + */ +void sched_arch_idle(void); +#if IS_USED(MODULE_SCHED_CB) || defined(DOXYGEN) /** * @brief Scheduler run callback * diff --git a/core/init.c b/core/init.c index 5b8e905fdf..a679867a37 100644 --- a/core/init.c +++ b/core/init.c @@ -53,6 +53,9 @@ static void *main_trampoline(void *arg) return NULL; } +static char main_stack[THREAD_STACKSIZE_MAIN]; +static char idle_stack[THREAD_STACKSIZE_IDLE]; + static void *idle_thread(void *arg) { (void)arg; @@ -64,17 +67,17 @@ static void *idle_thread(void *arg) return NULL; } -static char main_stack[THREAD_STACKSIZE_MAIN]; -static char idle_stack[THREAD_STACKSIZE_IDLE]; void kernel_init(void) { irq_disable(); - thread_create(idle_stack, sizeof(idle_stack), - THREAD_PRIORITY_IDLE, - THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST, - idle_thread, NULL, "idle"); + if (IS_USED(MODULE_CORE_IDLE_THREAD)) { + thread_create(idle_stack, sizeof(idle_stack), + THREAD_PRIORITY_IDLE, + THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST, + idle_thread, NULL, "idle"); + } thread_create(main_stack, sizeof(main_stack), THREAD_PRIORITY_MAIN, diff --git a/core/sched.c b/core/sched.c index b76c67de65..981c28b70b 100644 --- a/core/sched.c +++ b/core/sched.c @@ -80,11 +80,14 @@ int __attribute__((used)) sched_run(void) { sched_context_switch_request = 0; +#ifndef MODULE_CORE_IDLE_THREAD + while (!runqueue_bitcache) { + sched_arch_idle(); + } +#endif + thread_t *active_thread = (thread_t *)sched_active_thread; - /* The bitmask in runqueue_bitcache is never empty, - * since the threading should not be started before at least the idle thread was started. - */ int nextrq = bitarithm_lsb(runqueue_bitcache); thread_t *next_thread = container_of(sched_runqueues[nextrq].next->next, thread_t, rq_entry); diff --git a/makefiles/features_modules.inc.mk b/makefiles/features_modules.inc.mk index 3d69156e35..8a8bcbff76 100644 --- a/makefiles/features_modules.inc.mk +++ b/makefiles/features_modules.inc.mk @@ -28,3 +28,8 @@ endif # select cortexm_svc pseudomodule if the corresponding feature is used USEMODULE += $(filter cortexm_svc, $(FEATURES_USED)) + +# select core_idle_thread if the feature no_idle_thread is *not* used +ifeq (, $(filter no_idle_thread, $(FEATURES_USED))) + USEMODULE += core_idle_thread +endif