kernel/sched: Properly synchronize pend()

Kernel wait_q's and the thread pended_on backpointer are scheduler
state and need to be modified under the scheduler lock.  There was one
spot in pend() where they were not.

Also unpack z_remove_thread_from_ready_q() into an unsynchronized
utility so that it can be called by this process in a single lock
block.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2020-01-23 13:04:15 -08:00 committed by Anas Nashif
commit ed6b4fb21c

View file

@ -483,26 +483,33 @@ void z_thread_single_abort(struct k_thread *thread)
#endif
}
static void unready_thread(struct k_thread *thread)
{
if (z_is_thread_queued(thread)) {
_priq_run_remove(&_kernel.ready_q.runq, thread);
z_mark_thread_as_not_queued(thread);
}
update_cache(thread == _current);
}
void z_remove_thread_from_ready_q(struct k_thread *thread)
{
LOCKED(&sched_spinlock) {
if (z_is_thread_queued(thread)) {
_priq_run_remove(&_kernel.ready_q.runq, thread);
z_mark_thread_as_not_queued(thread);
}
update_cache(thread == _current);
unready_thread(thread);
}
}
static void pend(struct k_thread *thread, _wait_q_t *wait_q, s32_t timeout)
{
z_remove_thread_from_ready_q(thread);
z_mark_thread_as_pending(thread);
sys_trace_thread_pend(thread);
LOCKED(&sched_spinlock) {
unready_thread(thread);
z_mark_thread_as_pending(thread);
sys_trace_thread_pend(thread);
if (wait_q != NULL) {
thread->base.pended_on = wait_q;
z_priq_wait_add(&wait_q->waitq, thread);
if (wait_q != NULL) {
thread->base.pended_on = wait_q;
z_priq_wait_add(&wait_q->waitq, thread);
}
}
if (timeout != K_FOREVER) {
@ -546,9 +553,8 @@ ALWAYS_INLINE void z_unpend_thread_no_timeout(struct k_thread *thread)
LOCKED(&sched_spinlock) {
_priq_wait_remove(&pended_on(thread)->waitq, thread);
z_mark_thread_as_not_pending(thread);
thread->base.pended_on = NULL;
}
thread->base.pended_on = NULL;
}
#ifdef CONFIG_SYS_CLOCK_EXISTS