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 <andyross@google.com>
This commit is contained in:
Andy Ross 2024-03-08 08:42:08 -08:00 committed by Carles Cufí
parent 238b9be5ee
commit f2280d119d

View file

@ -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;
}
}
}