aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index ae5e1a19b9d6..2effcb71a478 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1686,6 +1686,39 @@ static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
1686 __release(rq2->lock); 1686 __release(rq2->lock);
1687} 1687}
1688 1688
1689#else /* CONFIG_SMP */
1690
1691/*
1692 * double_rq_lock - safely lock two runqueues
1693 *
1694 * Note this does not disable interrupts like task_rq_lock,
1695 * you need to do so manually before calling.
1696 */
1697static void double_rq_lock(struct rq *rq1, struct rq *rq2)
1698 __acquires(rq1->lock)
1699 __acquires(rq2->lock)
1700{
1701 BUG_ON(!irqs_disabled());
1702 BUG_ON(rq1 != rq2);
1703 raw_spin_lock(&rq1->lock);
1704 __acquire(rq2->lock); /* Fake it out ;) */
1705}
1706
1707/*
1708 * double_rq_unlock - safely unlock two runqueues
1709 *
1710 * Note this does not restore interrupts like task_rq_unlock,
1711 * you need to do so manually after calling.
1712 */
1713static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
1714 __releases(rq1->lock)
1715 __releases(rq2->lock)
1716{
1717 BUG_ON(rq1 != rq2);
1718 raw_spin_unlock(&rq1->lock);
1719 __release(rq2->lock);
1720}
1721
1689#endif 1722#endif
1690 1723
1691static void calc_load_account_idle(struct rq *this_rq); 1724static void calc_load_account_idle(struct rq *this_rq);
@@ -5448,6 +5481,58 @@ void __sched yield(void)
5448} 5481}
5449EXPORT_SYMBOL(yield); 5482EXPORT_SYMBOL(yield);
5450 5483
5484/**
5485 * yield_to - yield the current processor to another thread in
5486 * your thread group, or accelerate that thread toward the
5487 * processor it's on.
5488 *
5489 * It's the caller's job to ensure that the target task struct
5490 * can't go away on us before we can do any checks.
5491 *
5492 * Returns true if we indeed boosted the target task.
5493 */
5494bool __sched yield_to(struct task_struct *p, bool preempt)
5495{
5496 struct task_struct *curr = current;
5497 struct rq *rq, *p_rq;
5498 unsigned long flags;
5499 bool yielded = 0;
5500
5501 local_irq_save(flags);
5502 rq = this_rq();
5503
5504again:
5505 p_rq = task_rq(p);
5506 double_rq_lock(rq, p_rq);
5507 while (task_rq(p) != p_rq) {
5508 double_rq_unlock(rq, p_rq);
5509 goto again;
5510 }
5511
5512 if (!curr->sched_class->yield_to_task)
5513 goto out;
5514
5515 if (curr->sched_class != p->sched_class)
5516 goto out;
5517
5518 if (task_running(p_rq, p) || p->state)
5519 goto out;
5520
5521 yielded = curr->sched_class->yield_to_task(rq, p, preempt);
5522 if (yielded)
5523 schedstat_inc(rq, yld_count);
5524
5525out:
5526 double_rq_unlock(rq, p_rq);
5527 local_irq_restore(flags);
5528
5529 if (yielded)
5530 schedule();
5531
5532 return yielded;
5533}
5534EXPORT_SYMBOL_GPL(yield_to);
5535
5451/* 5536/*
5452 * This task is about to go to sleep on IO. Increment rq->nr_iowait so 5537 * This task is about to go to sleep on IO. Increment rq->nr_iowait so
5453 * that process accounting knows that this is a task in IO wait state. 5538 * that process accounting knows that this is a task in IO wait state.