diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-26 14:29:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-26 14:29:35 -0400 |
commit | 8f404faa72f4e458e7bd81ac75ce55ae829e953d (patch) | |
tree | 46b70d6d86fc619343b4986160bda5e46b86bb18 | |
parent | 729eb528c7e10a4828fece102872ec5255946f64 (diff) | |
parent | 06d8308c61e54346585b2691c13ee3f90cb6fb2f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/linux-2.6-hrt:
NOHZ: reevaluate idle sleep length after add_timer_on()
clocksource: revert: use init_timer_deferrable for clocksource_watchdog
-rw-r--r-- | include/linux/sched.h | 6 | ||||
-rw-r--r-- | kernel/sched.c | 43 | ||||
-rw-r--r-- | kernel/time/clocksource.c | 2 | ||||
-rw-r--r-- | kernel/timer.c | 10 |
4 files changed, 59 insertions, 2 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index fed07d03364e..6a1e7afb099b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1541,6 +1541,12 @@ static inline void idle_task_exit(void) {} | |||
1541 | 1541 | ||
1542 | extern void sched_idle_next(void); | 1542 | extern void sched_idle_next(void); |
1543 | 1543 | ||
1544 | #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) | ||
1545 | extern void wake_up_idle_cpu(int cpu); | ||
1546 | #else | ||
1547 | static inline void wake_up_idle_cpu(int cpu) { } | ||
1548 | #endif | ||
1549 | |||
1544 | #ifdef CONFIG_SCHED_DEBUG | 1550 | #ifdef CONFIG_SCHED_DEBUG |
1545 | extern unsigned int sysctl_sched_latency; | 1551 | extern unsigned int sysctl_sched_latency; |
1546 | extern unsigned int sysctl_sched_min_granularity; | 1552 | extern unsigned int sysctl_sched_min_granularity; |
diff --git a/kernel/sched.c b/kernel/sched.c index 28c73f07efb2..8dcdec6fe0fe 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -1052,6 +1052,49 @@ static void resched_cpu(int cpu) | |||
1052 | resched_task(cpu_curr(cpu)); | 1052 | resched_task(cpu_curr(cpu)); |
1053 | spin_unlock_irqrestore(&rq->lock, flags); | 1053 | spin_unlock_irqrestore(&rq->lock, flags); |
1054 | } | 1054 | } |
1055 | |||
1056 | #ifdef CONFIG_NO_HZ | ||
1057 | /* | ||
1058 | * When add_timer_on() enqueues a timer into the timer wheel of an | ||
1059 | * idle CPU then this timer might expire before the next timer event | ||
1060 | * which is scheduled to wake up that CPU. In case of a completely | ||
1061 | * idle system the next event might even be infinite time into the | ||
1062 | * future. wake_up_idle_cpu() ensures that the CPU is woken up and | ||
1063 | * leaves the inner idle loop so the newly added timer is taken into | ||
1064 | * account when the CPU goes back to idle and evaluates the timer | ||
1065 | * wheel for the next timer event. | ||
1066 | */ | ||
1067 | void wake_up_idle_cpu(int cpu) | ||
1068 | { | ||
1069 | struct rq *rq = cpu_rq(cpu); | ||
1070 | |||
1071 | if (cpu == smp_processor_id()) | ||
1072 | return; | ||
1073 | |||
1074 | /* | ||
1075 | * This is safe, as this function is called with the timer | ||
1076 | * wheel base lock of (cpu) held. When the CPU is on the way | ||
1077 | * to idle and has not yet set rq->curr to idle then it will | ||
1078 | * be serialized on the timer wheel base lock and take the new | ||
1079 | * timer into account automatically. | ||
1080 | */ | ||
1081 | if (rq->curr != rq->idle) | ||
1082 | return; | ||
1083 | |||
1084 | /* | ||
1085 | * We can set TIF_RESCHED on the idle task of the other CPU | ||
1086 | * lockless. The worst case is that the other CPU runs the | ||
1087 | * idle task through an additional NOOP schedule() | ||
1088 | */ | ||
1089 | set_tsk_thread_flag(rq->idle, TIF_NEED_RESCHED); | ||
1090 | |||
1091 | /* NEED_RESCHED must be visible before we test polling */ | ||
1092 | smp_mb(); | ||
1093 | if (!tsk_is_polling(rq->idle)) | ||
1094 | smp_send_reschedule(cpu); | ||
1095 | } | ||
1096 | #endif | ||
1097 | |||
1055 | #else | 1098 | #else |
1056 | static void __resched_task(struct task_struct *p, int tif_bit) | 1099 | static void __resched_task(struct task_struct *p, int tif_bit) |
1057 | { | 1100 | { |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 278534bbca95..7f60097d443a 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -174,7 +174,7 @@ static void clocksource_check_watchdog(struct clocksource *cs) | |||
174 | if (watchdog) | 174 | if (watchdog) |
175 | del_timer(&watchdog_timer); | 175 | del_timer(&watchdog_timer); |
176 | watchdog = cs; | 176 | watchdog = cs; |
177 | init_timer_deferrable(&watchdog_timer); | 177 | init_timer(&watchdog_timer); |
178 | watchdog_timer.function = clocksource_watchdog; | 178 | watchdog_timer.function = clocksource_watchdog; |
179 | 179 | ||
180 | /* Reset watchdog cycles */ | 180 | /* Reset watchdog cycles */ |
diff --git a/kernel/timer.c b/kernel/timer.c index 99b00a25f88b..b024106daa70 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -451,10 +451,18 @@ void add_timer_on(struct timer_list *timer, int cpu) | |||
451 | spin_lock_irqsave(&base->lock, flags); | 451 | spin_lock_irqsave(&base->lock, flags); |
452 | timer_set_base(timer, base); | 452 | timer_set_base(timer, base); |
453 | internal_add_timer(base, timer); | 453 | internal_add_timer(base, timer); |
454 | /* | ||
455 | * Check whether the other CPU is idle and needs to be | ||
456 | * triggered to reevaluate the timer wheel when nohz is | ||
457 | * active. We are protected against the other CPU fiddling | ||
458 | * with the timer by holding the timer base lock. This also | ||
459 | * makes sure that a CPU on the way to idle can not evaluate | ||
460 | * the timer wheel. | ||
461 | */ | ||
462 | wake_up_idle_cpu(cpu); | ||
454 | spin_unlock_irqrestore(&base->lock, flags); | 463 | spin_unlock_irqrestore(&base->lock, flags); |
455 | } | 464 | } |
456 | 465 | ||
457 | |||
458 | /** | 466 | /** |
459 | * mod_timer - modify a timer's timeout | 467 | * mod_timer - modify a timer's timeout |
460 | * @timer: the timer to be modified | 468 | * @timer: the timer to be modified |