From c0ba11b281d65c85dae1829fd9532decd3de8046 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Mon, 14 May 2018 14:46:27 -0700 Subject: [PATCH] kernel: Don't _arch_switch() to yourself The SMP testing missed the case where _Swap() decides to return back into the _current. Obviously there is no valid switch handle for the running thread into which we can restore, and everything blows up. (What happened is that the new scheduler code opened up a spot where k_thread_priority_set() does a _reschedule() unconditionally and doens't check to see whether or not it's needed like the old code). But that isn't incorrect! It's entirely possible that _Swap() may find that no thread is runnable except _current (due, for example, to another CPU racing the other thread you expected off to sleep or something). Don't blow up, check and return a noop. Signed-off-by: Andy Ross --- kernel/include/kswap.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/kernel/include/kswap.h b/kernel/include/kswap.h index a12e14b29ad..67bf94b4b2a 100644 --- a/kernel/include/kswap.h +++ b/kernel/include/kswap.h @@ -44,7 +44,7 @@ void _smp_release_global_lock(struct k_thread *thread); static inline unsigned int _Swap(unsigned int key) { struct k_thread *new_thread, *old_thread; - int ret; + int ret = 0; old_thread = _current; @@ -57,22 +57,24 @@ static inline unsigned int _Swap(unsigned int key) new_thread = _get_next_ready_thread(); - old_thread->swap_retval = -EAGAIN; + if (new_thread != old_thread) { + old_thread->swap_retval = -EAGAIN; #ifdef CONFIG_SMP - old_thread->base.active = 0; - new_thread->base.active = 1; + old_thread->base.active = 0; + new_thread->base.active = 1; - new_thread->base.cpu = _arch_curr_cpu()->id; + new_thread->base.cpu = _arch_curr_cpu()->id; - _smp_release_global_lock(new_thread); + _smp_release_global_lock(new_thread); #endif - _current = new_thread; - _arch_switch(new_thread->switch_handle, - &old_thread->switch_handle); + _current = new_thread; + _arch_switch(new_thread->switch_handle, + &old_thread->switch_handle); - ret = _current->swap_retval; + ret = _current->swap_retval; + } irq_unlock(key);