diff options
author | Tony Lindgren <tony@atomide.com> | 2006-03-06 18:42:45 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-06 21:40:44 -0500 |
commit | 69239749e1ac4f3496906aa4267cb9f61ce52c9c (patch) | |
tree | c64bc2c254b7fa81b50b11c851fe5c86ecdd83c1 | |
parent | f7c09bd972b7111b8c69bf57a189571edd4d4a7d (diff) |
[PATCH] fix next_timer_interrupt() for hrtimer
Also from Thomas Gleixner <tglx@linutronix.de>
Function next_timer_interrupt() got broken with a recent patch
6ba1b91213e81aa92b5cf7539f7d2a94ff54947c as sys_nanosleep() was moved to
hrtimer. This broke things as next_timer_interrupt() did not check hrtimer
tree for next event.
Function next_timer_interrupt() is needed with dyntick (CONFIG_NO_IDLE_HZ,
VST) implementations, as the system can be in idle when next hrtimer event
was supposed to happen. At least ARM and S390 currently use
next_timer_interrupt().
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/arm/kernel/time.c | 10 | ||||
-rw-r--r-- | include/linux/hrtimer.h | 4 | ||||
-rw-r--r-- | kernel/hrtimer.c | 35 | ||||
-rw-r--r-- | kernel/timer.c | 16 |
4 files changed, 61 insertions, 4 deletions
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index d7d932c02866..d6bd435a6857 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -422,12 +422,14 @@ static int timer_dyn_tick_disable(void) | |||
422 | void timer_dyn_reprogram(void) | 422 | void timer_dyn_reprogram(void) |
423 | { | 423 | { |
424 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; | 424 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; |
425 | unsigned long next, seq; | ||
425 | 426 | ||
426 | if (dyn_tick) { | 427 | if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) { |
427 | write_seqlock(&xtime_lock); | 428 | next = next_timer_interrupt(); |
428 | if (dyn_tick->state & DYN_TICK_ENABLED) | 429 | do { |
430 | seq = read_seqbegin(&xtime_lock); | ||
429 | dyn_tick->reprogram(next_timer_interrupt() - jiffies); | 431 | dyn_tick->reprogram(next_timer_interrupt() - jiffies); |
430 | write_sequnlock(&xtime_lock); | 432 | } while (read_seqretry(&xtime_lock, seq)); |
431 | } | 433 | } |
432 | } | 434 | } |
433 | 435 | ||
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 6361544bb6ae..6401c31d6add 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h | |||
@@ -116,6 +116,10 @@ extern int hrtimer_try_to_cancel(struct hrtimer *timer); | |||
116 | extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); | 116 | extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); |
117 | extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); | 117 | extern int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp); |
118 | 118 | ||
119 | #ifdef CONFIG_NO_IDLE_HZ | ||
120 | extern ktime_t hrtimer_get_next_event(void); | ||
121 | #endif | ||
122 | |||
119 | static inline int hrtimer_active(const struct hrtimer *timer) | 123 | static inline int hrtimer_active(const struct hrtimer *timer) |
120 | { | 124 | { |
121 | return timer->state == HRTIMER_PENDING; | 125 | return timer->state == HRTIMER_PENDING; |
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 5ae51f1bc7c8..14bc9cfa6399 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -505,6 +505,41 @@ ktime_t hrtimer_get_remaining(const struct hrtimer *timer) | |||
505 | return rem; | 505 | return rem; |
506 | } | 506 | } |
507 | 507 | ||
508 | #ifdef CONFIG_NO_IDLE_HZ | ||
509 | /** | ||
510 | * hrtimer_get_next_event - get the time until next expiry event | ||
511 | * | ||
512 | * Returns the delta to the next expiry event or KTIME_MAX if no timer | ||
513 | * is pending. | ||
514 | */ | ||
515 | ktime_t hrtimer_get_next_event(void) | ||
516 | { | ||
517 | struct hrtimer_base *base = __get_cpu_var(hrtimer_bases); | ||
518 | ktime_t delta, mindelta = { .tv64 = KTIME_MAX }; | ||
519 | unsigned long flags; | ||
520 | int i; | ||
521 | |||
522 | for (i = 0; i < MAX_HRTIMER_BASES; i++, base++) { | ||
523 | struct hrtimer *timer; | ||
524 | |||
525 | spin_lock_irqsave(&base->lock, flags); | ||
526 | if (!base->first) { | ||
527 | spin_unlock_irqrestore(&base->lock, flags); | ||
528 | continue; | ||
529 | } | ||
530 | timer = rb_entry(base->first, struct hrtimer, node); | ||
531 | delta.tv64 = timer->expires.tv64; | ||
532 | spin_unlock_irqrestore(&base->lock, flags); | ||
533 | delta = ktime_sub(delta, base->get_time()); | ||
534 | if (delta.tv64 < mindelta.tv64) | ||
535 | mindelta.tv64 = delta.tv64; | ||
536 | } | ||
537 | if (mindelta.tv64 < 0) | ||
538 | mindelta.tv64 = 0; | ||
539 | return mindelta; | ||
540 | } | ||
541 | #endif | ||
542 | |||
508 | /** | 543 | /** |
509 | * hrtimer_init - initialize a timer to the given clock | 544 | * hrtimer_init - initialize a timer to the given clock |
510 | * | 545 | * |
diff --git a/kernel/timer.c b/kernel/timer.c index fc6646fd5aab..8256f3f5ec0d 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -489,9 +489,21 @@ unsigned long next_timer_interrupt(void) | |||
489 | struct list_head *list; | 489 | struct list_head *list; |
490 | struct timer_list *nte; | 490 | struct timer_list *nte; |
491 | unsigned long expires; | 491 | unsigned long expires; |
492 | unsigned long hr_expires = MAX_JIFFY_OFFSET; | ||
493 | ktime_t hr_delta; | ||
492 | tvec_t *varray[4]; | 494 | tvec_t *varray[4]; |
493 | int i, j; | 495 | int i, j; |
494 | 496 | ||
497 | hr_delta = hrtimer_get_next_event(); | ||
498 | if (hr_delta.tv64 != KTIME_MAX) { | ||
499 | struct timespec tsdelta; | ||
500 | tsdelta = ktime_to_timespec(hr_delta); | ||
501 | hr_expires = timespec_to_jiffies(&tsdelta); | ||
502 | if (hr_expires < 3) | ||
503 | return hr_expires + jiffies; | ||
504 | } | ||
505 | hr_expires += jiffies; | ||
506 | |||
495 | base = &__get_cpu_var(tvec_bases); | 507 | base = &__get_cpu_var(tvec_bases); |
496 | spin_lock(&base->t_base.lock); | 508 | spin_lock(&base->t_base.lock); |
497 | expires = base->timer_jiffies + (LONG_MAX >> 1); | 509 | expires = base->timer_jiffies + (LONG_MAX >> 1); |
@@ -542,6 +554,10 @@ found: | |||
542 | } | 554 | } |
543 | } | 555 | } |
544 | spin_unlock(&base->t_base.lock); | 556 | spin_unlock(&base->t_base.lock); |
557 | |||
558 | if (time_before(hr_expires, expires)) | ||
559 | return hr_expires; | ||
560 | |||
545 | return expires; | 561 | return expires; |
546 | } | 562 | } |
547 | #endif | 563 | #endif |