aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2011-07-19 18:07:25 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2011-07-20 13:50:11 -0400
commitc5d753a55ac92e09816d410cd17093813f1a904b (patch)
tree162c63edcc463e18d50fb5b5be479785f02222c4
parent10f39bb1b2c1923ca73e70cb13aeee0e9b822d8f (diff)
sched: Add irq_{enter,exit}() to scheduler_ipi()
Ensure scheduler_ipi() calls irq_{enter,exit} when it does some actual work. Traditionally we never did any actual work from the resched IPI and all magic happened in the return from interrupt path. Now that we do do some work, we need to ensure irq_{enter,exit} are called so that we don't confuse things. This affects things like timekeeping, NO_HZ and RCU, basically everything with a hook in irq_enter/exit. Explicit examples of things going wrong are: sched_clock_cpu() -- has a callback when leaving NO_HZ state to take a new reading from GTOD and TSC. Without this callback, time is stuck in the past. RCU -- needs in_irq() to work in order to avoid some nasty deadlocks Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-rw-r--r--kernel/sched.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 9769c756ad66..1930ee19d98b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2544,13 +2544,9 @@ static int ttwu_remote(struct task_struct *p, int wake_flags)
2544} 2544}
2545 2545
2546#ifdef CONFIG_SMP 2546#ifdef CONFIG_SMP
2547static void sched_ttwu_pending(void) 2547static void sched_ttwu_do_pending(struct task_struct *list)
2548{ 2548{
2549 struct rq *rq = this_rq(); 2549 struct rq *rq = this_rq();
2550 struct task_struct *list = xchg(&rq->wake_list, NULL);
2551
2552 if (!list)
2553 return;
2554 2550
2555 raw_spin_lock(&rq->lock); 2551 raw_spin_lock(&rq->lock);
2556 2552
@@ -2563,9 +2559,45 @@ static void sched_ttwu_pending(void)
2563 raw_spin_unlock(&rq->lock); 2559 raw_spin_unlock(&rq->lock);
2564} 2560}
2565 2561
2562#ifdef CONFIG_HOTPLUG_CPU
2563
2564static void sched_ttwu_pending(void)
2565{
2566 struct rq *rq = this_rq();
2567 struct task_struct *list = xchg(&rq->wake_list, NULL);
2568
2569 if (!list)
2570 return;
2571
2572 sched_ttwu_do_pending(list);
2573}
2574
2575#endif /* CONFIG_HOTPLUG_CPU */
2576
2566void scheduler_ipi(void) 2577void scheduler_ipi(void)
2567{ 2578{
2568 sched_ttwu_pending(); 2579 struct rq *rq = this_rq();
2580 struct task_struct *list = xchg(&rq->wake_list, NULL);
2581
2582 if (!list)
2583 return;
2584
2585 /*
2586 * Not all reschedule IPI handlers call irq_enter/irq_exit, since
2587 * traditionally all their work was done from the interrupt return
2588 * path. Now that we actually do some work, we need to make sure
2589 * we do call them.
2590 *
2591 * Some archs already do call them, luckily irq_enter/exit nest
2592 * properly.
2593 *
2594 * Arguably we should visit all archs and update all handlers,
2595 * however a fair share of IPIs are still resched only so this would
2596 * somewhat pessimize the simple resched case.
2597 */
2598 irq_enter();
2599 sched_ttwu_do_pending(list);
2600 irq_exit();
2569} 2601}
2570 2602
2571static void ttwu_queue_remote(struct task_struct *p, int cpu) 2603static void ttwu_queue_remote(struct task_struct *p, int cpu)