Commit 69239749e1ac4f3496906aa4267cb9f61ce52c9c
Committed by
Linus Torvalds
1 parent
f7c09bd972
Exists in
master
and in
39 other branches
[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>
Showing 4 changed files with 61 additions and 4 deletions Side-by-side Diff
arch/arm/kernel/time.c
... | ... | @@ -422,12 +422,14 @@ |
422 | 422 | void timer_dyn_reprogram(void) |
423 | 423 | { |
424 | 424 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; |
425 | + unsigned long next, seq; | |
425 | 426 | |
426 | - if (dyn_tick) { | |
427 | - write_seqlock(&xtime_lock); | |
428 | - if (dyn_tick->state & DYN_TICK_ENABLED) | |
427 | + if (dyn_tick && (dyn_tick->state & DYN_TICK_ENABLED)) { | |
428 | + next = next_timer_interrupt(); | |
429 | + do { | |
430 | + seq = read_seqbegin(&xtime_lock); | |
429 | 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 |
include/linux/hrtimer.h
... | ... | @@ -116,6 +116,10 @@ |
116 | 116 | extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer); |
117 | 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 | 123 | static inline int hrtimer_active(const struct hrtimer *timer) |
120 | 124 | { |
121 | 125 | return timer->state == HRTIMER_PENDING; |
kernel/hrtimer.c
... | ... | @@ -505,6 +505,41 @@ |
505 | 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 | 544 | * hrtimer_init - initialize a timer to the given clock |
510 | 545 | * |
kernel/timer.c
... | ... | @@ -489,9 +489,21 @@ |
489 | 489 | struct list_head *list; |
490 | 490 | struct timer_list *nte; |
491 | 491 | unsigned long expires; |
492 | + unsigned long hr_expires = MAX_JIFFY_OFFSET; | |
493 | + ktime_t hr_delta; | |
492 | 494 | tvec_t *varray[4]; |
493 | 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 | 507 | base = &__get_cpu_var(tvec_bases); |
496 | 508 | spin_lock(&base->t_base.lock); |
497 | 509 | expires = base->timer_jiffies + (LONG_MAX >> 1); |
... | ... | @@ -542,6 +554,10 @@ |
542 | 554 | } |
543 | 555 | } |
544 | 556 | spin_unlock(&base->t_base.lock); |
557 | + | |
558 | + if (time_before(hr_expires, expires)) | |
559 | + return hr_expires; | |
560 | + | |
545 | 561 | return expires; |
546 | 562 | } |
547 | 563 | #endif |