[PATCH 02/02 -rt] Include an interval timer fortimeofday_periodic_hook

From: Steven Rostedt
Date: Mon Apr 03 2006 - 11:27:47 EST


This patch uses an interval timer that can be updated in interrupt
context without too much latency, so that the timeofday_periodic_hook
doesn't wrap if is is prevented from executing because of a high
priority task.

-- Steve

Signed-off-by: Steven Rostedt <rostedt@xxxxxxxxxxx>

Index: linux-2.6.16-rt12/kernel/time/timeofday.c
===================================================================
--- linux-2.6.16-rt12.orig/kernel/time/timeofday.c 2006-04-03 11:14:29.000000000 -0400
+++ linux-2.6.16-rt12/kernel/time/timeofday.c 2006-04-03 11:18:44.000000000 -0400
@@ -69,8 +69,19 @@ static struct timespec monotonic_time_of
* cycle_last:
* Value of the clocksource at the last timeofday_periodic_hook()
* (adjusted only minorly to account for rounded off cycles)
+ * cycle_last_interval:
+ * A value called at small intervals to prevent the cycle_last
+ * from wrapping. The difference is added to cycle_last_index
+ * to keep a running value of the time from the last call to
+ * timeofday_periodic_hook.
+ * cycle_last_index:
+ * The time called by the cycle update between calls
+ * to timeofday_periodic_hook. The cycle update can be done in
+ * interrupt context, where as the periodic hook is too heavy.
*/
static cycle_t cycle_last;
+static cycle_t cycle_last_interval;
+static cycle_t cycle_last_index;

/* [clocksource_interval variables]
* ts_interval:
@@ -271,7 +282,8 @@ static inline s64 __get_nsec_offset(void
cycle_now = read_clocksource(clock);

/* calculate the delta since the last timeofday_periodic_hook: */
- cycle_delta = (cycle_now - cycle_last) & clock->mask;
+ cycle_delta = (cycle_now - cycle_last_interval) & clock->mask;
+ cycle_delta += cycle_last_index;

/* convert to nanoseconds: */
ns_offset = cyc2ns(clock, ntp_adj, cycle_delta);
@@ -575,7 +587,8 @@ static int timeofday_resume_hook(struct
* time drift.
*/
suspend_end = read_persistent_clock();
- cycle_last = read_clocksource(clock);
+ cycle_last = cycle_last_interval = read_clocksource(clock);
+ cycle_last_index = 0;

/* calculate suspend time and add it to system time: */
suspend_time = suspend_end - suspend_start;
@@ -619,6 +632,48 @@ static int timeofday_init_device(void)

device_initcall(timeofday_init_device);

+static int timeofday_update_cycles(struct hrtimer *timer)
+{
+ unsigned long flags;
+
+ cycle_t cycle_now, cycle_delta;
+
+ write_seqlock_irqsave(&system_time_lock, flags);
+
+ /* read time source & calc time since last call: */
+ cycle_now = read_clocksource(clock);
+ cycle_delta = (cycle_now - cycle_last_interval) & clock->mask;
+ cycle_last_interval = cycle_now;
+
+ cycle_last_index += cycle_delta;
+
+ write_sequnlock_irqrestore(&system_time_lock, flags);
+
+ timer->expires.tv64 += TICK_NSEC;
+
+ return HRTIMER_RESTART;
+}
+
+static struct hrtimer cycle_update_timer;
+
+static void timeofday_init_update_cycles(void)
+{
+ ktime_t now;
+
+ hrtimer_init(&cycle_update_timer, CLOCK_MONOTONIC,
+ HRTIMER_ABS);
+
+ cycle_update_timer.function = timeofday_update_cycles;
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+ cycle_update_timer.mode = HRTIMER_CB_IRQSAFE;
+#endif
+ now = ktime_get();
+ now.tv64 += TICK_NSEC;
+
+ hrtimer_start(&cycle_update_timer, now, HRTIMER_ABS);
+}
+
/**
* timeofday_periodic_hook - Does periodic update of timekeeping values.
* @unused: unused value
@@ -652,10 +707,12 @@ static void timeofday_periodic_hook(unsi
/* read time source & calc time since last call: */
cycle_now = read_clocksource(clock);
check_periodic_interval(cycle_now);
- cycle_delta = (cycle_now - cycle_last) & clock->mask;
+ cycle_delta = (cycle_now - cycle_last_interval) & clock->mask;
+ cycle_delta += cycle_last_index;
+ cycle_last = cycle_last_interval = cycle_now;
+ cycle_last_index = 0;

delta_nsec = cyc2ns_fixed_rem(ts_interval, &cycle_delta, &remainder);
- cycle_last = (cycle_now - cycle_delta)&clock->mask;

/* update system_time: */
__increment_system_time(delta_nsec);
@@ -681,7 +738,8 @@ static void timeofday_periodic_hook(unsi
next = get_next_clocksource();
if (next != clock) {
/* immediately set new cycle_last: */
- cycle_last = read_clocksource(next);
+ cycle_last = cycle_last_interval = read_clocksource(next);
+ cycle_last_index = 0;
/* update cycle_now to avoid problems in accumulation later: */
cycle_now = cycle_last;
/* swap clocksources: */
@@ -728,7 +786,8 @@ static void timeofday_periodic_hook(unsi
if (cycle_delta) {
delta_nsec = cyc2ns_rem(&old_clock, ntp_adj,
cycle_delta, &remainder);
- cycle_last = cycle_now;
+ cycle_last = cycle_last_interval = cycle_now;
+ cycle_last_index = 0;
__increment_system_time(delta_nsec);
ntp_advance(delta_nsec);
}
@@ -810,7 +869,7 @@ void __init timeofday_init(void)
clock = get_next_clocksource();

/* initialize cycle_last offset base: */
- cycle_last = read_clocksource(clock);
+ cycle_last = cycle_last_interval = read_clocksource(clock);

/* initialize wall_time_offset to now: */
/* XXX - this should be something like ns_to_ktime() */
@@ -828,6 +887,8 @@ void __init timeofday_init(void)

write_sequnlock_irqrestore(&system_time_lock, flags);

+ timeofday_init_update_cycles();
+
/* install timeofday_periodic_hook timer: */
init_timer(&timeofday_timer);
timeofday_timer.function = timeofday_periodic_hook;


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/