diff options
author | John Stultz <john.stultz@linaro.org> | 2011-08-10 11:31:03 -0700 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2011-08-10 14:55:23 -0700 |
commit | dce75a8c71819ed4c7efdcd53c9b6f6356dc8cb5 (patch) | |
tree | 76d25888bb83814fc1f9d5f8838483730ca59882 | |
parent | 54da23b720d5d612f8f1669f9ed3744008fb7382 (diff) | |
download | blackbird-op-linux-dce75a8c71819ed4c7efdcd53c9b6f6356dc8cb5.tar.gz blackbird-op-linux-dce75a8c71819ed4c7efdcd53c9b6f6356dc8cb5.zip |
alarmtimers: Add alarm_forward functionality
In order to avoid wasting time expiring and re-adding very high freq
periodic alarmtimers, introduce alarm_forward() which is similar to
hrtimer_forward and moves the timer to the next future expiration time
and returns the number of overruns.
CC: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r-- | include/linux/alarmtimer.h | 2 | ||||
-rw-r--r-- | kernel/time/alarmtimer.c | 37 |
2 files changed, 38 insertions, 1 deletions
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 0289eb29e794..17535963b274 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -42,4 +42,6 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, void alarm_start(struct alarm *alarm, ktime_t start, ktime_t period); void alarm_cancel(struct alarm *alarm); +u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); + #endif diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 55e634ea6054..f03b04291b6f 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -347,6 +347,41 @@ void alarm_cancel(struct alarm *alarm) } + +u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval) +{ + u64 overrun = 1; + ktime_t delta; + + delta = ktime_sub(now, alarm->node.expires); + + if (delta.tv64 < 0) + return 0; + + if (unlikely(delta.tv64 >= interval.tv64)) { + s64 incr = ktime_to_ns(interval); + + overrun = ktime_divns(delta, incr); + + alarm->node.expires = ktime_add_ns(alarm->node.expires, + incr*overrun); + + if (alarm->node.expires.tv64 > now.tv64) + return overrun; + /* + * This (and the ktime_add() below) is the + * correction for exact: + */ + overrun++; + } + + alarm->node.expires = ktime_add(alarm->node.expires, interval); + return overrun; +} + + + + /** * clock2alarm - helper that converts from clockid to alarmtypes * @clockid: clockid. @@ -376,7 +411,7 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, /* Re-add periodic timers */ if (alarm->period.tv64) { - alarm->node.expires = ktime_add(now, alarm->period); + ptr->it_overrun += alarm_forward(alarm, now, alarm->period); return ALARMTIMER_RESTART; } return ALARMTIMER_NORESTART; |