summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched_rt.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index fe9da6084c87..64a8f0aa117b 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1192,7 +1192,6 @@ static int push_rt_task(struct rq *rq)
{
struct task_struct *next_task;
struct rq *lowest_rq;
- int paranoid = RT_MAX_TRIES;
if (!rq->rt.overloaded)
return 0;
@@ -1226,23 +1225,34 @@ static int push_rt_task(struct rq *rq)
struct task_struct *task;
/*
* find lock_lowest_rq releases rq->lock
- * so it is possible that next_task has changed.
- * If it has, then try again.
+ * so it is possible that next_task has migrated.
+ *
+ * We need to make sure that the task is still on the same
+ * run-queue and is also still the next task eligible for
+ * pushing.
*/
task = pick_next_pushable_task(rq);
- if (unlikely(task != next_task) && task && paranoid--) {
- put_task_struct(next_task);
- next_task = task;
- goto retry;
+ if (task_cpu(next_task) == rq->cpu && task == next_task) {
+ /*
+ * If we get here, the task hasnt moved at all, but
+ * it has failed to push. We will not try again,
+ * since the other cpus will pull from us when they
+ * are ready.
+ */
+ dequeue_pushable_task(rq, next_task);
+ goto out;
}
+ if (!task)
+ /* No more tasks, just exit */
+ goto out;
+
/*
- * Once we have failed to push this task, we will not
- * try again, since the other cpus will pull from us
- * when they are ready
+ * Something has shifted, try again.
*/
- dequeue_pushable_task(rq, next_task);
- goto out;
+ put_task_struct(next_task);
+ next_task = task;
+ goto retry;
}
deactivate_task(rq, next_task, 0);