summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_tc.c
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2011-11-20 05:32:12 +0000
committerlstewart <lstewart@FreeBSD.org>2011-11-20 05:32:12 +0000
commit1c7932d8700beaf35065d777ce68888c107cb24a (patch)
tree4349e54bc1cc0ae830281701ae51f5b3b1d38efa /sys/kern/kern_tc.c
parentad330644b2506d314c5d82704b50881e609948c6 (diff)
downloadFreeBSD-src-1c7932d8700beaf35065d777ce68888c107cb24a.zip
FreeBSD-src-1c7932d8700beaf35065d777ce68888c107cb24a.tar.gz
- Provide a sysctl interface to change the active system clock at runtime.
- Wrap [get]{bin,nano,micro}[up]time() functions of sys/time.h to allow requesting time from either the feedback or the feed-forward clock. If a feedback (e.g. ntpd) and feed-forward (e.g. radclock) daemon are both running on the system, both kernel clocks are updated but only one serves time. - Add similar wrappers for the feed-forward difference clock. Committed on behalf of Julien Ridoux and Darryl Veitch from the University of Melbourne, Australia, as part of the FreeBSD Foundation funded "Feed-Forward Clock Synchronization Algorithms" project. For more information, see http://www.synclab.org/radclock/ Submitted by: Julien Ridoux (jridoux at unimelb edu au)
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r--sys/kern/kern_tc.c320
1 files changed, 318 insertions, 2 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index 90095f6..66e26d0 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -177,6 +177,144 @@ tc_delta(struct timehands *th)
* the comment in <sys/time.h> for a description of these 12 functions.
*/
+#ifdef FFCLOCK
+static void
+fbclock_binuptime(struct bintime *bt)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ *bt = th->th_offset;
+ bintime_addx(bt, th->th_scale * tc_delta(th));
+ } while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_nanouptime(struct timespec *tsp)
+{
+ struct bintime bt;
+
+ binuptime(&bt);
+ bintime2timespec(&bt, tsp);
+}
+
+static void
+fbclock_microuptime(struct timeval *tvp)
+{
+ struct bintime bt;
+
+ binuptime(&bt);
+ bintime2timeval(&bt, tvp);
+}
+
+static void
+fbclock_bintime(struct bintime *bt)
+{
+
+ binuptime(bt);
+ bintime_add(bt, &boottimebin);
+}
+
+static void
+fbclock_nanotime(struct timespec *tsp)
+{
+ struct bintime bt;
+
+ bintime(&bt);
+ bintime2timespec(&bt, tsp);
+}
+
+static void
+fbclock_microtime(struct timeval *tvp)
+{
+ struct bintime bt;
+
+ bintime(&bt);
+ bintime2timeval(&bt, tvp);
+}
+
+static void
+fbclock_getbinuptime(struct bintime *bt)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ *bt = th->th_offset;
+ } while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getnanouptime(struct timespec *tsp)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ bintime2timespec(&th->th_offset, tsp);
+ } while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getmicrouptime(struct timeval *tvp)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ bintime2timeval(&th->th_offset, tvp);
+ } while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getbintime(struct bintime *bt)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ *bt = th->th_offset;
+ } while (gen == 0 || gen != th->th_generation);
+ bintime_add(bt, &boottimebin);
+}
+
+static void
+fbclock_getnanotime(struct timespec *tsp)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ *tsp = th->th_nanotime;
+ } while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getmicrotime(struct timeval *tvp)
+{
+ struct timehands *th;
+ unsigned int gen;
+
+ do {
+ th = timehands;
+ gen = th->th_generation;
+ *tvp = th->th_microtime;
+ } while (gen == 0 || gen != th->th_generation);
+}
+#else /* !FFCLOCK */
void
binuptime(struct bintime *bt)
{
@@ -313,6 +451,7 @@ getmicrotime(struct timeval *tvp)
*tvp = th->th_microtime;
} while (gen == 0 || gen != th->th_generation);
}
+#endif /* FFCLOCK */
#ifdef FFCLOCK
/*
@@ -322,6 +461,8 @@ getmicrotime(struct timeval *tvp)
* necessary.
*/
+int sysclock_active = SYSCLOCK_FBCK;
+
/* Feed-forward clock estimates kept updated by the synchronization daemon. */
struct ffclock_estimate ffclock_estimate;
struct bintime ffclock_boottime; /* Feed-forward boot time estimate. */
@@ -329,6 +470,38 @@ uint32_t ffclock_status; /* Feed-forward clock status. */
int8_t ffclock_updated; /* New estimates are available. */
struct mtx ffclock_mtx; /* Mutex on ffclock_estimate. */
+struct sysclock_ops {
+ int active;
+ void (*binuptime) (struct bintime *bt);
+ void (*nanouptime) (struct timespec *tsp);
+ void (*microuptime) (struct timeval *tvp);
+ void (*bintime) (struct bintime *bt);
+ void (*nanotime) (struct timespec *tsp);
+ void (*microtime) (struct timeval *tvp);
+ void (*getbinuptime) (struct bintime *bt);
+ void (*getnanouptime) (struct timespec *tsp);
+ void (*getmicrouptime) (struct timeval *tvp);
+ void (*getbintime) (struct bintime *bt);
+ void (*getnanotime) (struct timespec *tsp);
+ void (*getmicrotime) (struct timeval *tvp);
+};
+
+static struct sysclock_ops sysclock = {
+ .active = SYSCLOCK_FBCK,
+ .binuptime = fbclock_binuptime,
+ .nanouptime = fbclock_nanouptime,
+ .microuptime = fbclock_microuptime,
+ .bintime = fbclock_bintime,
+ .nanotime = fbclock_nanotime,
+ .microtime = fbclock_microtime,
+ .getbinuptime = fbclock_getbinuptime,
+ .getnanouptime = fbclock_getnanouptime,
+ .getmicrouptime = fbclock_getmicrouptime,
+ .getbintime = fbclock_getbintime,
+ .getnanotime = fbclock_getnanotime,
+ .getmicrotime = fbclock_getmicrotime
+};
+
struct fftimehands {
struct ffclock_estimate cest;
struct bintime tick_time;
@@ -621,6 +794,46 @@ ffclock_change_tc(struct timehands *th)
fftimehands = ffth;
}
+static void
+change_sysclock(int new_sysclock)
+{
+
+ sysclock.active = new_sysclock;
+
+ switch (sysclock.active) {
+ case SYSCLOCK_FBCK:
+ sysclock.binuptime = fbclock_binuptime;
+ sysclock.nanouptime = fbclock_nanouptime;
+ sysclock.microuptime = fbclock_microuptime;
+ sysclock.bintime = fbclock_bintime;
+ sysclock.nanotime = fbclock_nanotime;
+ sysclock.microtime = fbclock_microtime;
+ sysclock.getbinuptime = fbclock_getbinuptime;
+ sysclock.getnanouptime = fbclock_getnanouptime;
+ sysclock.getmicrouptime = fbclock_getmicrouptime;
+ sysclock.getbintime = fbclock_getbintime;
+ sysclock.getnanotime = fbclock_getnanotime;
+ sysclock.getmicrotime = fbclock_getmicrotime;
+ break;
+ case SYSCLOCK_FFWD:
+ sysclock.binuptime = ffclock_binuptime;
+ sysclock.nanouptime = ffclock_nanouptime;
+ sysclock.microuptime = ffclock_microuptime;
+ sysclock.bintime = ffclock_bintime;
+ sysclock.nanotime = ffclock_nanotime;
+ sysclock.microtime = ffclock_microtime;
+ sysclock.getbinuptime = ffclock_getbinuptime;
+ sysclock.getnanouptime = ffclock_getnanouptime;
+ sysclock.getmicrouptime = ffclock_getmicrouptime;
+ sysclock.getbintime = ffclock_getbintime;
+ sysclock.getnanotime = ffclock_getnanotime;
+ sysclock.getmicrotime = ffclock_getmicrotime;
+ break;
+ default:
+ break;
+ }
+}
+
/*
* Retrieve feed-forward counter and time of last kernel tick.
*/
@@ -731,6 +944,90 @@ ffclock_read_counter(ffcounter *ffcount)
*ffcount += delta;
}
+
+void
+binuptime(struct bintime *bt)
+{
+
+ sysclock.binuptime(bt);
+}
+
+void
+nanouptime(struct timespec *tsp)
+{
+
+ sysclock.nanouptime(tsp);
+}
+
+void
+microuptime(struct timeval *tvp)
+{
+
+ sysclock.microuptime(tvp);
+}
+
+void
+bintime(struct bintime *bt)
+{
+
+ sysclock.bintime(bt);
+}
+
+void
+nanotime(struct timespec *tsp)
+{
+
+ sysclock.nanotime(tsp);
+}
+
+void
+microtime(struct timeval *tvp)
+{
+
+ sysclock.microtime(tvp);
+}
+
+void
+getbinuptime(struct bintime *bt)
+{
+
+ sysclock.getbinuptime(bt);
+}
+
+void
+getnanouptime(struct timespec *tsp)
+{
+
+ sysclock.getnanouptime(tsp);
+}
+
+void
+getmicrouptime(struct timeval *tvp)
+{
+
+ sysclock.getmicrouptime(tvp);
+}
+
+void
+getbintime(struct bintime *bt)
+{
+
+ sysclock.getbintime(bt);
+}
+
+void
+getnanotime(struct timespec *tsp)
+{
+
+ sysclock.getnanotime(tsp);
+}
+
+void
+getmicrotime(struct timeval *tvp)
+{
+
+ sysclock.getmicrouptime(tvp);
+}
#endif /* FFCLOCK */
/*
@@ -971,6 +1268,11 @@ tc_windup(void)
scale /= th->th_counter->tc_frequency;
th->th_scale = scale * 2;
+#ifdef FFCLOCK
+ if (sysclock_active != sysclock.active)
+ change_sysclock(sysclock_active);
+#endif
+
/*
* Now that the struct timehands is again consistent, set the new
* generation number, making sure to not make it zero.
@@ -980,8 +1282,21 @@ tc_windup(void)
th->th_generation = ogen;
/* Go live with the new struct timehands. */
- time_second = th->th_microtime.tv_sec;
- time_uptime = th->th_offset.sec;
+#ifdef FFCLOCK
+ switch (sysclock_active) {
+ case SYSCLOCK_FBCK:
+#endif
+ time_second = th->th_microtime.tv_sec;
+ time_uptime = th->th_offset.sec;
+#ifdef FFCLOCK
+ break;
+ case SYSCLOCK_FFWD:
+ time_second = fftimehands->tick_time_lerp.sec;
+ time_uptime = fftimehands->tick_time_lerp.sec - ffclock_boottime.sec;
+ break;
+ }
+#endif
+
timehands = th;
}
@@ -1261,6 +1576,7 @@ inittimecounter(void *dummy)
#ifdef FFCLOCK
ffclock_init();
+ change_sysclock(sysclock_active);
#endif
/* warm up new timecounter (again) and get rolling. */
(void)timecounter->tc_get_timecount(timecounter);
OpenPOWER on IntegriCloud