aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/timer.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2007-03-25 08:31:17 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-25 17:57:34 -0400
commit9501b6cf5541f0d576d566a463f1e7d3eaaab4eb (patch)
tree7983c4cc3c82e465cfe88a7fd67e39dbed72e1e0 /kernel/timer.c
parent317ec6cd00f25d05d153a780bc178c5335f320ee (diff)
[PATCH] dynticks: fix hrtimer rounding error in next_timer_interrupt
The rework of next_timer_interrupt() fixed the timer wheel bugs, but invented a rounding error versus the next hrtimer event. This is caused by the conversion of the hrtimer internal representation to relative jiffies. This causes bug #8100: http://bugzilla.kernel.org/show_bug.cgi?id=8100 next_timer_interrupt() returns "now" in such a case and causes the code in tick_nohz_stop_sched_tick() to trigger the timer softirq, which is bogus as no timer is due for expiry. This results in an endless context switching between idle and ksoftirqd until a timer is due for expiry. Modify the hrtimer evaluation so that, it returns now + 1, when the conversion results in a delta < 1 jiffie. It's confirmed to resolve bug #8100 Reported-by: Emil Karlson <jkarlson@cc.hut.fi> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/timer.c')
-rw-r--r--kernel/timer.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index 797cccb86431..440048acaea1 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -695,15 +695,28 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
695{ 695{
696 ktime_t hr_delta = hrtimer_get_next_event(); 696 ktime_t hr_delta = hrtimer_get_next_event();
697 struct timespec tsdelta; 697 struct timespec tsdelta;
698 unsigned long delta;
698 699
699 if (hr_delta.tv64 == KTIME_MAX) 700 if (hr_delta.tv64 == KTIME_MAX)
700 return expires; 701 return expires;
701 702
702 if (hr_delta.tv64 <= TICK_NSEC) 703 /*
703 return now; 704 * Expired timer available, let it expire in the next tick
705 */
706 if (hr_delta.tv64 <= 0)
707 return now + 1;
704 708
705 tsdelta = ktime_to_timespec(hr_delta); 709 tsdelta = ktime_to_timespec(hr_delta);
706 now += timespec_to_jiffies(&tsdelta); 710 delta = timespec_to_jiffies(&tsdelta);
711 /*
712 * Take rounding errors in to account and make sure, that it
713 * expires in the next tick. Otherwise we go into an endless
714 * ping pong due to tick_nohz_stop_sched_tick() retriggering
715 * the timer softirq
716 */
717 if (delta < 1)
718 delta = 1;
719 now += delta;
707 if (time_before(now, expires)) 720 if (time_before(now, expires))
708 return now; 721 return now;
709 return expires; 722 return expires;