From f2280d119d3a3a69d66b3f3516fc1d4e3d453b8b Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 8 Mar 2024 08:42:08 -0800 Subject: [PATCH] kernel/sched: Don't touch deadline values on queued threads k_thread_deadline_set() would modify the thread's deadline and then, if it was in the run queue, requeue it to put it at the right spot. Sounds right, right? It's wrong. The deadline field is part of the thread priority, so this results in a mis-ordered list. For dlist backends, that's benign as the removal works anyway, but if CONFIG_SCHED_SCALABLE=y we've now broken the sorting order of an in-tree item and corrupted the rbtree! Fixes #69935 Signed-off-by: Andy Ross --- kernel/sched.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kernel/sched.c b/kernel/sched.c index 93005ce6ba..57974044f9 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1280,12 +1280,21 @@ static inline void z_vrfy_k_thread_priority_set(k_tid_t thread, int prio) void z_impl_k_thread_deadline_set(k_tid_t tid, int deadline) { struct k_thread *thread = tid; + int32_t newdl = k_cycle_get_32() + deadline; + /* The prio_deadline field changes the sorting order, so can't + * change it while the thread is in the run queue (dlists + * actually are benign as long as we requeue it before we + * release the lock, but an rbtree will blow up if we break + * sorting!) + */ K_SPINLOCK(&_sched_spinlock) { - thread->base.prio_deadline = k_cycle_get_32() + deadline; if (z_is_thread_queued(thread)) { dequeue_thread(thread); + thread->base.prio_deadline = newdl; queue_thread(thread); + } else { + thread->base.prio_deadline = newdl; } } }