aboutsummaryrefslogtreecommitdiff
path: root/kernel/sched/core.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2013-02-13 12:56:14 +0100
committerAlexander Graf <agraf@suse.de>2013-02-13 12:56:14 +0100
commitdd92d6f2749c43ebab91c4762a1bc79e6523e936 (patch)
tree6e6730bdd09284679c0861df6d0fcbec08ea7a87 /kernel/sched/core.c
parentb9e3e208935e95ad62bd1b1bc4408c23a9ae3ada (diff)
parentb0da5bec30eca7ffbb2c89afa6fe503fd418d3a6 (diff)
Merge commit 'origin/next' into kvm-ppc-next
Diffstat (limited to 'kernel/sched/core.c')
-rw-r--r--kernel/sched/core.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 0533496b622..01edad9b5d7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4316,7 +4316,10 @@ EXPORT_SYMBOL(yield);
* It's the caller's job to ensure that the target task struct
* can't go away on us before we can do any checks.
*
- * Returns true if we indeed boosted the target task.
+ * Returns:
+ * true (>0) if we indeed boosted the target task.
+ * false (0) if we failed to boost the target.
+ * -ESRCH if there's no task to yield to.
*/
bool __sched yield_to(struct task_struct *p, bool preempt)
{
@@ -4330,6 +4333,15 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
again:
p_rq = task_rq(p);
+ /*
+ * If we're the only runnable task on the rq and target rq also
+ * has only one task, there's absolutely no point in yielding.
+ */
+ if (rq->nr_running == 1 && p_rq->nr_running == 1) {
+ yielded = -ESRCH;
+ goto out_irq;
+ }
+
double_rq_lock(rq, p_rq);
while (task_rq(p) != p_rq) {
double_rq_unlock(rq, p_rq);
@@ -4337,13 +4349,13 @@ again:
}
if (!curr->sched_class->yield_to_task)
- goto out;
+ goto out_unlock;
if (curr->sched_class != p->sched_class)
- goto out;
+ goto out_unlock;
if (task_running(p_rq, p) || p->state)
- goto out;
+ goto out_unlock;
yielded = curr->sched_class->yield_to_task(rq, p, preempt);
if (yielded) {
@@ -4356,11 +4368,12 @@ again:
resched_task(p_rq->curr);
}
-out:
+out_unlock:
double_rq_unlock(rq, p_rq);
+out_irq:
local_irq_restore(flags);
- if (yielded)
+ if (yielded > 0)
schedule();
return yielded;