[PATCH 02/02 -rt] Include an interval timer for timeofday_periodic_hook

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <[email protected]>

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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux