Author: lstewart
Date: Sun Nov 20 05:32:12 2011
New Revision: 227747
URL: http://svn.freebsd.org/changeset/base/227747

Log:
  - 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)

Modified:
  head/sys/kern/kern_ffclock.c
  head/sys/kern/kern_tc.c
  head/sys/sys/timeffc.h

Modified: head/sys/kern/kern_ffclock.c
==============================================================================
--- head/sys/kern/kern_ffclock.c        Sun Nov 20 01:48:22 2011        
(r227746)
+++ head/sys/kern/kern_ffclock.c        Sun Nov 20 05:32:12 2011        
(r227747)
@@ -31,6 +31,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/timeffc.h>
 
@@ -127,3 +129,215 @@ ffclock_difftime(ffcounter ffdelta, stru
                bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL);
        }
 }
+
+/*
+ * Sysctl for the Feed-Forward Clock.
+ */
+
+static int ffclock_version = 2;
+SYSCTL_NODE(_kern, OID_AUTO, ffclock, CTLFLAG_RW, 0,
+    "Feed-Forward Clock Support");
+SYSCTL_INT(_kern_ffclock, OID_AUTO, version, CTLFLAG_RD, &ffclock_version, 0,
+    "Version of Feed-Forward Clock Support");
+
+/*
+ * Sysctl to select which clock is read when calling any of the
+ * [get]{bin,nano,micro}[up]time() functions.
+ */
+char *sysclocks[] = {"feedback", "feed-forward"};
+
+#define        NUM_SYSCLOCKS (sizeof(sysclocks) / sizeof(*sysclocks))
+
+/* Report or change the active timecounter hardware. */
+static int
+sysctl_kern_ffclock_choice(SYSCTL_HANDLER_ARGS)
+{
+       struct sbuf *s;
+       int clk, error;
+
+       s = sbuf_new_for_sysctl(NULL, NULL, 16 * NUM_SYSCLOCKS, req);
+       if (s == NULL)
+               return (ENOMEM);
+
+       for (clk = 0; clk < NUM_SYSCLOCKS; clk++) {
+               sbuf_cat(s, sysclocks[clk]);
+               if (clk + 1 < NUM_SYSCLOCKS)
+                       sbuf_cat(s, " ");
+       }
+       error = sbuf_finish(s);
+       sbuf_delete(s);
+
+       return (error);
+}
+
+SYSCTL_PROC(_kern_ffclock, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
+    0, 0, sysctl_kern_ffclock_choice, "A", "Clock paradigms available");
+
+extern int sysclock_active;
+
+static int
+sysctl_kern_ffclock_active(SYSCTL_HANDLER_ARGS)
+{
+       char newclock[32];
+       int error;
+
+       switch (sysclock_active) {
+       case SYSCLOCK_FBCK:
+               strlcpy(newclock, sysclocks[SYSCLOCK_FBCK], sizeof(newclock));
+               break;
+       case SYSCLOCK_FFWD:
+               strlcpy(newclock, sysclocks[SYSCLOCK_FFWD], sizeof(newclock));
+               break;
+       }
+
+       error = sysctl_handle_string(oidp, &newclock[0], sizeof(newclock), req);
+       if (error != 0 || req->newptr == NULL)
+               return (error);
+       if (strncmp(newclock, sysclocks[SYSCLOCK_FBCK],
+           sizeof(sysclocks[SYSCLOCK_FBCK])) == 0)
+               sysclock_active = SYSCLOCK_FBCK;
+       else if (strncmp(newclock, sysclocks[SYSCLOCK_FFWD],
+           sizeof(sysclocks[SYSCLOCK_FFWD])) == 0)
+               sysclock_active = SYSCLOCK_FFWD;
+       else
+               return (EINVAL);
+
+       return (error);
+}
+
+SYSCTL_PROC(_kern_ffclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW,
+    0, 0, sysctl_kern_ffclock_active, "A", "Kernel clock selected");
+
+/*
+ * High level functions to access the Feed-Forward Clock.
+ */
+void
+ffclock_bintime(struct bintime *bt)
+{
+
+       ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+}
+
+void
+ffclock_nanotime(struct timespec *tsp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+       bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microtime(struct timeval *tvp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+       bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_getbintime(struct bintime *bt)
+{
+
+       ffclock_abstime(NULL, bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+}
+
+void
+ffclock_getnanotime(struct timespec *tsp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+       bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_getmicrotime(struct timeval *tvp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+       bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_binuptime(struct bintime *bt)
+{
+
+       ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+}
+
+void
+ffclock_nanouptime(struct timespec *tsp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+       bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microuptime(struct timeval *tvp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+       bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_getbinuptime(struct bintime *bt)
+{
+
+       ffclock_abstime(NULL, bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+}
+
+void
+ffclock_getnanouptime(struct timespec *tsp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+       bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_getmicrouptime(struct timeval *tvp)
+{
+       struct bintime bt;
+
+       ffclock_abstime(NULL, &bt, NULL,
+           FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+       bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt)
+{
+
+       ffclock_difftime(ffdelta, bt, NULL);
+}
+
+void
+ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp)
+{
+       struct bintime bt;
+
+       ffclock_difftime(ffdelta, &bt, NULL);
+       bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp)
+{
+       struct bintime bt;
+
+       ffclock_difftime(ffdelta, &bt, NULL);
+       bintime2timeval(&bt, tvp);
+}

Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c     Sun Nov 20 01:48:22 2011        (r227746)
+++ head/sys/kern/kern_tc.c     Sun Nov 20 05:32:12 2011        (r227747)
@@ -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-forwar
 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);

Modified: head/sys/sys/timeffc.h
==============================================================================
--- head/sys/sys/timeffc.h      Sun Nov 20 01:48:22 2011        (r227746)
+++ head/sys/sys/timeffc.h      Sun Nov 20 05:32:12 2011        (r227747)
@@ -56,6 +56,13 @@ struct ffclock_estimate {
 #ifdef _KERNEL
 
 /*
+ * Index into the sysclocks array for obtaining the ASCII name of a particular
+ * sysclock.
+ */
+#define        SYSCLOCK_FBCK   0
+#define        SYSCLOCK_FFWD   1
+
+/*
  * Parameters of counter characterisation required by feed-forward algorithms.
  */
 #define        FFCLOCK_SKM_SCALE       1024
@@ -128,6 +135,35 @@ void ffclock_abstime(ffcounter *ffcount,
 void ffclock_difftime(ffcounter ffdelta, struct bintime *bt,
     struct bintime *error_bound);
 
+/*
+ * Wrapper routines to return current absolute time using the feed-forward
+ * clock. These functions are named after those defined in <sys/time.h>, which
+ * contains a description of the original ones.
+ */
+void ffclock_bintime(struct bintime *bt);
+void ffclock_nanotime(struct timespec *tsp);
+void ffclock_microtime(struct timeval *tvp);
+
+void ffclock_getbintime(struct bintime *bt);
+void ffclock_getnanotime(struct timespec *tsp);
+void ffclock_getmicrotime(struct timeval *tvp);
+
+void ffclock_binuptime(struct bintime *bt);
+void ffclock_nanouptime(struct timespec *tsp);
+void ffclock_microuptime(struct timeval *tvp);
+
+void ffclock_getbinuptime(struct bintime *bt);
+void ffclock_getnanouptime(struct timespec *tsp);
+void ffclock_getmicrouptime(struct timeval *tvp);
+
+/*
+ * Wrapper routines to convert a time interval specified in ffcounter units 
into
+ * seconds using the current feed-forward clock estimates.
+ */
+void ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt);
+void ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp);
+void ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp);
+
 #endif /* _KERNEL */
 #endif /* __BSD_VISIBLE */
 #endif /* _SYS_TIMEFF_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to