From 7a4affe47db86075eb36519049d047f6facab378 Mon Sep 17 00:00:00 2001 From: "Bjoern B. Brandenburg" Date: Tue, 2 Mar 2010 11:51:07 -0500 Subject: Bugfix: PSN-EDF should only requeue tasks that are not scheduled Requeue a task that is already scheduled will cause it to be effectively in the runqueue twice since scheduled tasks are conceptually the head of the queue. If a task is still scheduled, then schedule() will do the right thing and do the requeuing if necessary. This fixes crashes reported by Glenn and Andrea. --- litmus/sched_psn_edf.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'litmus') diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c index 3a93124e24f6..d37f045768d5 100644 --- a/litmus/sched_psn_edf.c +++ b/litmus/sched_psn_edf.c @@ -258,28 +258,27 @@ static void psnedf_task_wake_up(struct task_struct *task) release_at(task, now); sched_trace_task_release(task); } - requeue(task, edf); + + /* Only add to ready queue if it is not the currently-scheduled + * task. This could be the case if a task was woken up concurrently + * on a remote CPU before the executing CPU got around to actually + * de-scheduling the task, i.e., wake_up() raced with schedule() + * and won. + */ + if (pedf->scheduled != task) + requeue(task, edf); + spin_unlock_irqrestore(&pedf->slock, flags); TRACE_TASK(task, "wake up done\n"); } static void psnedf_task_block(struct task_struct *t) { - psnedf_domain_t *pedf = task_pedf(t); - /* only running tasks can block, thus t is in no queue */ TRACE_TASK(t, "block at %llu, state=%d\n", litmus_clock(), t->state); BUG_ON(!is_realtime(t)); BUG_ON(is_queued(t)); - - /* if this task is dead, then we need to reset pedf->schedule now - * as we might get rescheduled before task_exit executes - */ - if(unlikely(t->state == TASK_DEAD)) { - TRACE_TASK(t, "Dead, setting scheduled = NULL\n"); - pedf->scheduled = NULL; - } } static void psnedf_task_exit(struct task_struct * t) -- cgit v1.2.2