From 370f926bad275d64913391dfd6b869b02184fb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Wed, 5 Nov 2014 11:38:40 +0100 Subject: [PATCH] core: `sched_switch()` switch if not on runqueue Fixes #1935. `sched_switch()` should not only switch if the other priority is higher, but also if the current thread was moved from the runqueue. --- core/include/sched.h | 13 +++++++++---- core/sched.c | 12 +++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/core/include/sched.h b/core/include/sched.h index d4d4c1eef..09098df05 100644 --- a/core/include/sched.h +++ b/core/include/sched.h @@ -114,11 +114,16 @@ int sched_run(void); void sched_set_status(tcb_t *process, unsigned int status); /** - * @brief Compare thread priorities and yield() (or set - * @ref sched_context_switch_request if inISR()) when @p other_prio is - * higher (has a lower value) than the current thread's priority + * @brief Yield if approriate. * - * @param[in] other_prio The priority of the target thread + * @details Either yield if other_prio is higher than the current priority, + * or if the current thread is not on the runqueue. + * + * Depending on whether the current execution is in an ISR (inISR()), + * thread_yield_higher() is called or @ref sched_context_switch_request is set, + * respectively. + * + * @param[in] other_prio The priority of the target thread. */ void sched_switch(uint16_t other_prio); diff --git a/core/sched.c b/core/sched.c index 9875c83bf..6b7f96053 100644 --- a/core/sched.c +++ b/core/sched.c @@ -153,19 +153,25 @@ void sched_switch(uint16_t other_prio) int in_isr = inISR(); tcb_t *active_thread = (tcb_t *) sched_active_thread; uint16_t current_prio = active_thread->priority; + int on_runqueue = (active_thread->status >= STATUS_ON_RUNQUEUE); - DEBUG("sched_switch: active pid=%" PRIkernel_pid" prio=%" PRIu16 + DEBUG("sched_switch: active pid=%" PRIkernel_pid" prio=%" PRIu16 " on_runqueue=%i " ", other_prio=%" PRIu16 " in_isr=%i\n", - active_thread->pid, current_prio, other_prio, in_isr); + active_thread->pid, current_prio, on_runqueue, other_prio, in_isr); - if (current_prio > other_prio) { + if (!on_runqueue || (current_prio > other_prio)) { if (in_isr) { + DEBUG("sched_switch: setting sched_context_switch_request.\n"); sched_context_switch_request = 1; } else { + DEBUG("sched_switch: yielding immediately.\n"); thread_yield_higher(); } } + else { + DEBUG("sched_switch: continuing without yield.\n"); + } } NORETURN void sched_task_exit(void)