diff --git a/core/include/sched.h b/core/include/sched.h index d731cde19a..181a31755d 100644 --- a/core/include/sched.h +++ b/core/include/sched.h @@ -137,9 +137,12 @@ typedef enum { /** * @brief Triggers the scheduler to schedule the next thread - * @returns 1 if sched_active_thread/sched_active_pid was changed, 0 otherwise. + * + * @returns The new thread to schedule if sched_active_thread/sched_active_pid + * was changed, + * @returns NULL if the active thread was not changed. */ -int sched_run(void); +thread_t *sched_run(void); /** * @brief Set the status of the specified process diff --git a/core/sched.c b/core/sched.c index 28e1f48184..21ef5ba577 100644 --- a/core/sched.c +++ b/core/sched.c @@ -138,21 +138,20 @@ static void _unschedule(thread_t *active_thread) #endif } -int __attribute__((used)) sched_run(void) +thread_t *__attribute__((used)) sched_run(void) { thread_t *active_thread = thread_get_active(); + thread_t *previous_thread = active_thread; - if (!IS_USED(MODULE_CORE_IDLE_THREAD)) { - if (!runqueue_bitcache) { - if (active_thread) { - _unschedule(active_thread); - active_thread = NULL; - } - - do { - sched_arch_idle(); - } while (!runqueue_bitcache); + if (!IS_USED(MODULE_CORE_IDLE_THREAD) && !runqueue_bitcache) { + if (active_thread) { + _unschedule(active_thread); + active_thread = NULL; } + + do { + sched_arch_idle(); + } while (!runqueue_bitcache); } sched_context_switch_request = 0; @@ -168,39 +167,51 @@ int __attribute__((used)) sched_run(void) : active_thread->pid), next_thread->pid); - if (active_thread == next_thread) { - DEBUG("sched_run: done, sched_active_thread was not changed.\n"); - return 0; - } + next_thread->status = STATUS_RUNNING; - if (active_thread) { - _unschedule(active_thread); + if (previous_thread == next_thread) { +#ifdef MODULE_SCHED_CB + /* Call the sched callback again only if the active thread is NULL. When + * active_thread is NULL, there was a sleep in between descheduling the + * previous thread and scheduling the new thread. Call the callback here + * again ensures that the time sleeping doesn't count as running the + * previous thread + */ + if (sched_cb && !active_thread) { + sched_cb(KERNEL_PID_UNDEF, next_thread->pid); + } +#endif + DEBUG("sched_run: done, sched_active_thread was not changed.\n"); } + else { + if (active_thread) { + _unschedule(active_thread); + } + + sched_active_pid = next_thread->pid; + sched_active_thread = next_thread; #ifdef MODULE_SCHED_CB - if (sched_cb) { - sched_cb(KERNEL_PID_UNDEF, next_thread->pid); - } + if (sched_cb) { + sched_cb(KERNEL_PID_UNDEF, next_thread->pid); + } #endif - next_thread->status = STATUS_RUNNING; - sched_active_pid = next_thread->pid; - sched_active_thread = next_thread; #ifdef PICOLIBC_TLS - _set_tls(next_thread->tls); + _set_tls(next_thread->tls); #endif #ifdef MODULE_MPU_STACK_GUARD - mpu_configure( - 2, /* MPU region 2 */ - (uintptr_t)sched_active_thread->stack_start + 31, /* Base Address (rounded up) */ - MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */ - ); + mpu_configure( + 2, /* MPU region 2 */ + (uintptr_t)next_thread->stack_start + 31, /* Base Address (rounded up) */ + MPU_ATTR(1, AP_RO_RO, 0, 1, 0, 1, MPU_SIZE_32B) /* Attributes and Size */ + ); #endif + DEBUG("sched_run: done, changed sched_active_thread.\n"); + } - DEBUG("sched_run: done, changed sched_active_thread.\n"); - - return 1; + return next_thread; } void sched_set_status(thread_t *process, thread_status_t status)