summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/alarmtimer.h2
-rw-r--r--kernel/time/alarmtimer.c37
2 files changed, 38 insertions, 1 deletions
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h
index 0289eb29e79..17535963b27 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 55e634ea605..f03b04291b6 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;