]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Implement NTP style PLL time slewing
authorVMware, Inc <>
Mon, 26 Jul 2010 18:14:55 +0000 (11:14 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Mon, 26 Jul 2010 18:14:55 +0000 (11:14 -0700)
This change extends tools time sync to use the core ideas (and
system call) from NTP's time synchronization algorithm.

I tested this using ATTS for these guests: SLES11-64, RHEL5.4-64,
RHEL4.8-32, WinXP-32, Win7-64.  All of the results describe are
ignoring time spikes caused by apparent time falling behind and
catching up (which are not expected to be corrected by tools
timesync).

* Win7-64 hit a bug in the testing framework.
* WinXP-32 looked good (but unchaged from before).
* RHEL4.8-32 looks good (I'm using a 1000Hz kernel using the TSC,
so the lost tick compensation bug hits very severely and thus
provides a good test case for timesync).
* SLES11-64: Stayed within 1.5ms (no data for before).
* RHEL5.4-64: Stayed within 300us (before change it was 25ms).

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/services/plugins/timeSync/Makefile.am
open-vm-tools/services/plugins/timeSync/pllLinux.c [new file with mode: 0644]
open-vm-tools/services/plugins/timeSync/pllNone.c [new file with mode: 0644]
open-vm-tools/services/plugins/timeSync/slewAdjtime.c
open-vm-tools/services/plugins/timeSync/slewLinux.c
open-vm-tools/services/plugins/timeSync/timeSync.c
open-vm-tools/services/plugins/timeSync/timeSync.h

index b80c8feb3e876caf86726e70e5a4e75434fa23e0..7d7ce6522fd94cd4fcbd40ec107d8b834005b7b4 100644 (file)
@@ -33,11 +33,14 @@ libtimeSync_la_SOURCES += timeSyncPosix.c
 
 if SOLARIS
 libtimeSync_la_SOURCES += slewAdjtime.c
+libtimeSync_la_SOURCES += pllNone.c
 endif
 if FREEBSD
 libtimeSync_la_SOURCES += slewAdjtime.c
+libtimeSync_la_SOURCES += pllNone.c
 endif
 if LINUX
 libtimeSync_la_SOURCES += slewLinux.c
+libtimeSync_la_SOURCES += pllLinux.c
 endif
 
diff --git a/open-vm-tools/services/plugins/timeSync/pllLinux.c b/open-vm-tools/services/plugins/timeSync/pllLinux.c
new file mode 100644 (file)
index 0000000..feb3ed7
--- /dev/null
@@ -0,0 +1,188 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file pllLinux.c
+ *
+ * Implementation of the NTP PLL using Linux's adjtimex system call.
+ */
+
+#include "timeSync.h"
+#include "timeSyncPosix.h"
+
+#include <errno.h>
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include "vm_assert.h"
+
+
+static void
+TimeSyncLogPLLState(const char *prefix, struct timex *tx)
+{
+   g_debug("%s : off %ld freq %ld maxerr %ld esterr %ld status %d "
+           "const %ld precision %ld tolerance %ld tick %ld\n",
+           prefix, tx->offset, tx->freq, tx->maxerror, tx->esterror, 
+           tx->status, tx->constant, tx->precision, tx->tolerance, tx->tick);
+}
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLSupported --                                             */ /**
+ *
+ * Report whether the platform supports an NTP style Type-II Phase Locked
+ * Loop for correcting the time.
+ *
+ * @return TRUE iff NTP Phase Locked Loop is supported.
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLSupported(void)
+{
+   return TRUE;
+}
+
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLSetFrequency --                                          */ /**
+ *
+ * Set the frequency of the PLL.  
+ *
+ * @param[in] ppmCorrection  The parts per million error that should be 
+ *                           corrected.  This value is the ppm shifted 
+ *                           left by 16 to match NTP.
+ *
+ * @return TRUE on success.
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLSetFrequency(int64 ppmCorrection)
+{
+   struct timex tx;
+   int error;
+
+   tx.modes = ADJ_FREQUENCY;
+   tx.freq = ppmCorrection;
+
+   error = adjtimex(&tx);
+   if (error == -1) {
+      g_debug("%s: adjtimex failed: %d %s\n", __FUNCTION__,
+              error, strerror(errno));
+         return FALSE;
+   }
+   TimeSyncLogPLLState(__FUNCTION__, &tx);
+
+   return TRUE;
+}
+
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLUpdate --                                                */ /**
+ *
+ * Updates the PLL with a new offset.
+ *
+ * @param[in] offset         The offset between the host and the guest.
+ *
+ * @return TRUE on success.
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLUpdate(int64 offset)
+{
+   struct timex tx;
+   int error;
+
+   if (offset < -500000) {
+      offset = -500000;
+      g_debug("%s: clamped offset at -500000\n", __FUNCTION__);
+   }
+   if (offset > 500000) {
+      offset = 500000;
+      g_debug("%s: clamped offset at 500000\n", __FUNCTION__);
+   }
+
+
+   tx.modes = ADJ_OFFSET | ADJ_MAXERROR | ADJ_ESTERROR;
+   tx.offset = offset;
+   tx.esterror = 0;
+   tx.maxerror = 0;
+
+   error = adjtimex(&tx);
+   if (error == -1) {
+      g_debug("%s: adjtimex set offset failed: %d %s\n", __FUNCTION__,
+              error, strerror(errno));
+         return FALSE;
+   }
+   TimeSyncLogPLLState(__FUNCTION__, &tx);
+
+   /* Ensure that the kernel discipline is in the right mode.  STA_PLLs
+    * should be set and STA_UNSYNC should not be set.  
+    * 
+    * The time constant is a bit trickier.  In "Computer Network Time
+    * Synchronization" the terms used are "time constant" and "poll
+    * exponent" where time constant = 2 ^ poll exponent.  Valid values for
+    * the poll exponent are 4 through 17, corresponding to a range of 16s
+    * to 131072s (36 hours).  On linux things are a bit different though:
+    * tx.constant appears to be the poll exponent and when trying to set
+    * the poll exponent, tx.constant should be set to poll exponent - 4.
+    *
+    * We want to set the time constant to as low a value as possible.  The
+    * core NTP PLL that the kernel discipline implements is built assuming
+    * that there is a clock filter with a variable delay of up to 8.
+    * Since TimeSyncReadHostAndGuest retries if the error is large, we
+    * don't need to implement the clock filter.  Hence we want a time
+    * constant of 60/8 = 7, but settle for the lowest available: 16.  This
+    * allows us to react to changes relatively fast.
+    */
+   if (tx.constant != 4) {
+      tx.modes = ADJ_TIMECONST;
+      tx.constant = 0;
+      error = adjtimex(&tx);
+      if (error == -1) {
+         g_debug("%s: adjtimex set time constant failed: %d %s\n", __FUNCTION__,
+                 error, strerror(errno));
+         return FALSE;
+      }
+      g_debug("Set PLL time constant\n");
+      TimeSyncLogPLLState(__FUNCTION__, &tx);
+   }
+   if ((tx.status & STA_PLL) != STA_PLL || (tx.status & STA_UNSYNC) != 0) {
+      tx.modes = ADJ_STATUS;
+      tx.status = STA_PLL;
+      error = adjtimex(&tx);
+      if (error == -1) {
+         g_debug("%s: adjtimex set status failed: %d %s\n", __FUNCTION__,
+                 error, strerror(errno));
+         return FALSE;
+      }
+      g_debug("Set PLL status\n");
+      TimeSyncLogPLLState(__FUNCTION__, &tx);
+   }
+   return TRUE;
+}
diff --git a/open-vm-tools/services/plugins/timeSync/pllNone.c b/open-vm-tools/services/plugins/timeSync/pllNone.c
new file mode 100644 (file)
index 0000000..00bc8e7
--- /dev/null
@@ -0,0 +1,90 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file pllNone.c
+ *
+ * Null implementation of the NTP PLL.
+ */
+
+#include "timeSync.h"
+
+#include "vm_assert.h"
+
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLSupported --                                             */ /**
+ *
+ * Report whether the platform supports an NTP style Type-II Phase Locked
+ * Loop for correcting the time.
+ *
+ * @return TRUE iff NTP Phase Locked Loop is supported.
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLSupported(void)
+{
+   return FALSE;
+}
+
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLSetFrequency --                                          */ /**
+ *
+ * Set the frequency of the PLL.  
+ *
+ * @param[in] ppmCorrection  The parts per million error that should be 
+ *                           corrected.  This value is the ppm shifted 
+ *                           left by 16 to match NTP.
+ *
+ * @return FALSE
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLSetFrequency(int64 ppmCorrection)
+{
+   NOT_IMPLEMENTED();
+   return FALSE;
+}
+
+
+/*
+ ******************************************************************************
+ * TimeSync_PLLUpdate --                                                */ /**
+ *
+ * Updates the PLL with a new offset.
+ *
+ * @param[in] offset         The offset between the host and the guest.
+ *
+ * @return FALSE
+ *
+ ******************************************************************************
+ */
+
+Bool
+TimeSync_PLLUpdate(int64 offset)
+{
+   NOT_IMPLEMENTED();
+   return FALSE;
+}
index 2a0f9018c3a5ea9c116aea398e1485a6c8c005dc..8f6534662166f809e1c11628589ba5b53a3a9a29 100644 (file)
@@ -63,13 +63,15 @@ TimeSync_DisableTimeSlew(void)
 
 /*
  ******************************************************************************
- * TimeSync_EnableTimeSlew --                                           */ /**
+ * TimeSync_Slew --                                                     */ /**
  *
  * Slew the clock, correcting 'delta' microseconds.  timeSyncPeriod is
- * ignored by this implementation.
+ * ignored by this implementation.  Report the amount of the previous
+ * correction that has not been applied.
  *
- * @param[in] delta              Time difference in us.
- * @param[in] timeSyncPeriod     Time interval in us.
+ * @param[in]  delta              Correction to apply in us.
+ * @param[in]  timeSyncPeriod     Time interval in us.
+ * @param[out] remaining          Amount of previous correction not applied.
  *
  * @return TRUE on success.
  *
@@ -77,8 +79,9 @@ TimeSync_DisableTimeSlew(void)
  */
 
 Bool
-TimeSync_EnableTimeSlew(int64 delta,
-                        int64 timeSyncPeriod)
+TimeSync_Slew(int64 delta,
+              int64 timeSyncPeriod,
+              int64 *remaining)
 {
    struct timeval tx;
    struct timeval oldTx;
@@ -92,5 +95,8 @@ TimeSync_EnableTimeSlew(int64 delta,
       return FALSE;
    }
    g_debug("time slew start.\n");
+
+   *remaining = (int64)oldTx.tv_sec * US_PER_SEC + (int64)oldTx.tv_usec;
+
    return TRUE;
 }
index 3b78b07a3dc6fd35ed7a415efc1496be398544b0..0cb3f44d9d14191637f83536c4a943abb8009372 100644 (file)
@@ -82,17 +82,22 @@ TimeSync_DisableTimeSlew(void)
 
 /*
  ******************************************************************************
- * TimeSync_EnableTimeSlew --                                           */ /**
+ * TimeSync_Slew --                                                     */ /**
  *
  * Slew the clock so that the time difference is covered within the
- * timeSyncPeriod. timeSyncPeriod is the interval of the time sync loop and we
- * intend to catch up delta us.
+ * timeSyncPeriod. timeSyncPeriod is the interval of the time sync loop
+ * and we intend to catch up delta us.  Report the amount of the previous
+ * correction that has not been applied (this may be negative if more than
+ * timeSyncPeriod elapsed since the last call).
  *
  * This changes the tick frequency and hence needs to be reset after the time
  * sync is achieved.
  *
- * @param[in] delta              Time difference in us.
- * @param[in] timeSyncPeriod     Time interval in us.
+ * All times are in microseconds.
+ *
+ * @param[in]  delta              Correction to apply.
+ * @param[in]  timeSyncPeriod     Time interval.
+ * @param[out] remaining          Amount of previous correction not applied.
  *
  * @return TRUE on success.
  *
@@ -100,33 +105,54 @@ TimeSync_DisableTimeSlew(void)
  */
 
 Bool
-TimeSync_EnableTimeSlew(int64 delta,
-                        int64 timeSyncPeriod)
+TimeSync_Slew(int64 delta,
+              int64 timeSyncPeriod,
+              int64 *remaining)
 {
+   static int64 startTime = 0;
+   static int64 tickLength;
+   static int64 deltaRequested;
+
    struct timex tx;
    int error;
-   int64 tick;
+   int64 now;
 
    ASSERT(timeSyncPeriod > 0);
 
+   if (!TimeSync_GetCurrentTime(&now)) {
+      return FALSE;
+   }
+
+   if (startTime != 0) {
+      int64 ticksElapsed = (now - startTime) / tickLength;
+      int64 deltaApplied = ticksElapsed * (tickLength - TICK_INCR_NOMINAL);
+      *remaining = deltaRequested - deltaApplied;
+   }
+
    /*
-    * Set the tick so that delta time is corrected in timeSyncPeriod period.
-    * tick is the number of microseconds added per clock tick. We adjust this
-    * so that we get the desired delta + the timeSyncPeriod in timeSyncPeriod
-    * interval.
+    * Set the tick length so that delta time is corrected in
+    * timeSyncPeriod period.  tick is the number of microseconds added per
+    * clock tick. We adjust this so that we get the desired delta + the
+    * timeSyncPeriod in timeSyncPeriod interval.
     */
-   tx.modes = ADJ_TICK;
-   tick = (timeSyncPeriod + delta) /
-          ((timeSyncPeriod / US_PER_SEC) * USER_HZ);
-   if (tick > TICK_INCR_MAX) {
-      tick = TICK_INCR_MAX;
-   } else if (tick < TICK_INCR_MIN) {
-      tick = TICK_INCR_MIN;
+   tickLength = 
+      (timeSyncPeriod + delta) / ((timeSyncPeriod / US_PER_SEC) * USER_HZ);
+   if (tickLength > TICK_INCR_MAX) {
+      tickLength = TICK_INCR_MAX;
+   } else if (tickLength < TICK_INCR_MIN) {
+      tickLength = TICK_INCR_MIN;
    }
-   tx.tick = tick;
+   tx.tick = tickLength;
+   tx.modes = ADJ_TICK;
+
+   ASSERT(delta != 0 || tickLength == TICK_INCR_NOMINAL);
+   
+   startTime = now;
+   deltaRequested = delta;
 
    error = adjtimex(&tx);
    if (error == -1) {
+      startTime = 0;
       g_debug("adjtimex failed: %s\n", strerror(errno));
       return FALSE;
    }
index cd4fea5bc2d54dee9719cd809d07c347a28ec2f2..f2dffccce8c1035e9ddc41520cf097492d036dad 100644 (file)
@@ -115,23 +115,40 @@ VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
 #define TIMESYNC_MAX_SAMPLES 4
 #define TIMESYNC_GOOD_SAMPLE_THRESHOLD 2000
 
+/* Once the error drops below TIMESYNC_PLL_ACTIVATE, activate the PLL.
+ * 500ppm error acumulated over a 60 second interval can produce 30ms of
+ * error. */
+#define TIMESYNC_PLL_ACTIVATE (30 * 1000) /* 30ms. */
+/* If the error goes above TIMESYNC_PLL_UNSYNC, deactivate the PLL. */
+#define TIMESYNC_PLL_UNSYNC (2 * TIMESYNC_PLL_ACTIVATE)
+/* Period during which the frequency error of guest time is measured. */
+#define TIMESYNC_CALIBRATION_DURATION (15 * 60 * US_PER_SEC) /* 15min. */
+
 typedef enum TimeSyncState {
    TIMESYNC_INITIALIZING,
    TIMESYNC_STOPPED,
    TIMESYNC_RUNNING,
 } TimeSyncState;
 
+typedef enum TimeSyncSlewState {
+   TimeSyncUncalibrated,
+   TimeSyncCalibrating,
+   TimeSyncPLL,
+} TimeSyncSlewState;
+
 typedef struct TimeSyncData {
-   gboolean       slewActive;
-   gboolean       slewCorrection;
-   uint32         slewPercentCorrection;
-   uint32         timeSyncPeriod;         /* In seconds. */
-   TimeSyncState  state;
-   GSource        *timer;
+   gboolean           slewActive;
+   gboolean           slewCorrection;
+   uint32             slewPercentCorrection;
+   uint32             timeSyncPeriod;         /* In seconds. */
+   TimeSyncState      state;
+   TimeSyncSlewState  slewState;
+   GSource           *timer;
 } TimeSyncData;
 
 
 static void TimeSyncSetSlewState(TimeSyncData *data, gboolean active);
+static void TimeSyncResetSlew(TimeSyncData *data);
 
 /**
  * Read the time reported by the Host OS.
@@ -371,8 +388,18 @@ TimeSyncStepTime(TimeSyncData *data, int64 adjustment)
 
 
 /**
- * Slew the guest OS time advancement to correct the time.  Only correct a
- * portion of the error to avoid overcorrection.
+ * Slew the guest OS time advancement to correct the time.
+ *
+ * In addition to standard slewing (implemented via TimeSync_Slew), we
+ * also support using an NTP style PLL to slew the time.  The PLL can take
+ * a while to end up with an accurate measurement of the frequency error,
+ * so before entering PLL mode we calibrate the frequency error over a
+ * period of TIMESYNC_PLL_ACTIVATE seconds.  
+ *
+ * When using standard slewing, only correct slewPercentCorrection of the
+ * error.  This is to avoid overcorrection when the error is mis-measured,
+ * or overcorrection caused by the daemon waking up later than it is
+ * supposed to leaving the slew in place for longer than anticpiated.
  *
  * @param[in]  data              Structure tracking time sync state.
  * @param[in]  adjustment        Amount to correct the guest time.
@@ -381,10 +408,76 @@ TimeSyncStepTime(TimeSyncData *data, int64 adjustment)
 static gboolean
 TimeSyncSlewTime(TimeSyncData *data, int64 adjustment)
 {
+   static int64 calibrationStart;
+   static int64 calibrationAdjustment;
+
+   int64 now;
+   int64 remaining = 0;
    int64 timeSyncPeriodUS = data->timeSyncPeriod * US_PER_SEC;
    int64 slewDiff = (adjustment * data->slewPercentCorrection) / 100;
    
-   return TimeSync_EnableTimeSlew(slewDiff, timeSyncPeriodUS);
+   if (!TimeSync_GetCurrentTime(&now)) {
+      return FALSE;
+   }
+
+   if (adjustment > TIMESYNC_PLL_UNSYNC && 
+       data->slewState != TimeSyncUncalibrated) {
+      g_debug("Adjustment too large (%"FMT64"d), resetting PLL state.\n", 
+              adjustment);
+      data->slewState = TimeSyncUncalibrated;
+   }
+
+   if (data->slewState == TimeSyncUncalibrated) {
+      g_debug("Slewing time: adjustment %"FMT64"d\n", adjustment);
+      if (!TimeSync_Slew(slewDiff, timeSyncPeriodUS, &remaining)) {
+         data->slewState = TimeSyncUncalibrated;
+         return FALSE;
+      }
+      if (adjustment < TIMESYNC_PLL_ACTIVATE && TimeSync_PLLSupported()) {
+         g_debug("Starting PLL calibration.\n");
+         calibrationStart = now;
+         /* Starting out the calibration period we are adjustment behind,
+          * but have already requested to correct slewDiff of that. */
+         calibrationAdjustment = slewDiff - adjustment;
+         data->slewState = TimeSyncCalibrating;
+      }
+   } else if (data->slewState == TimeSyncCalibrating) {
+      if (now > calibrationStart + TIMESYNC_CALIBRATION_DURATION) {
+         int64 ppmErr;
+         /* Reset slewing to nominal and find out remaining slew. */
+         TimeSync_Slew(0, timeSyncPeriodUS, &remaining);
+         calibrationAdjustment += adjustment;
+         calibrationAdjustment -= remaining;
+         ppmErr = ((1000000 * calibrationAdjustment) << 16) / 
+                   (now - calibrationStart);
+         if (ppmErr >> 16 < 500 && ppmErr >> 16 > -500) {
+            g_debug("Activating PLL ppmEst=%"FMT64"d (%"FMT64"d)\n", 
+                    ppmErr >> 16, ppmErr);
+            TimeSync_PLLUpdate(adjustment);
+            TimeSync_PLLSetFrequency(ppmErr);
+            data->slewState = TimeSyncPLL;
+         } else {
+            /* PPM error is too large to try the PLL. */
+            g_debug("PPM error too large: %"FMT64"d (%"FMT64"d) "
+                    "not activating PLL\n", ppmErr >> 16, ppmErr);
+            data->slewState = TimeSyncUncalibrated;
+         }
+      } else {
+         g_debug("Calibrating error: adjustment %"FMT64"d\n", adjustment);
+         if (!TimeSync_Slew(slewDiff, timeSyncPeriodUS, &remaining)) {
+            return FALSE;
+         }
+         calibrationAdjustment += slewDiff;
+         calibrationAdjustment -= remaining;
+      }
+   } else {
+      ASSERT(data->slewState == TimeSyncPLL);
+      g_debug("Updating PLL: adjustment %"FMT64"d\n", adjustment);
+      if (!TimeSync_PLLUpdate(adjustment)) {
+         TimeSyncResetSlew(data);
+      }
+   }
+   return TRUE;
 }
 
 
@@ -397,7 +490,14 @@ TimeSyncSlewTime(TimeSyncData *data, int64 adjustment)
 static void
 TimeSyncResetSlew(TimeSyncData *data)
 {
-   TimeSyncSlewTime(data, 0);
+   int64 remaining;
+   int64 timeSyncPeriodUS = data->timeSyncPeriod * US_PER_SEC;
+   data->slewState = TimeSyncUncalibrated;
+   TimeSync_Slew(0, timeSyncPeriodUS, &remaining);
+   if (TimeSync_PLLSupported()) {
+      TimeSync_PLLUpdate(0);
+      TimeSync_PLLSetFrequency(0);
+   }
 }
 
 
@@ -817,6 +917,7 @@ ToolsOnLoad(ToolsAppCtx *ctx)
    data->slewCorrection = FALSE;
    data->slewPercentCorrection = TIMESYNC_PERCENT_CORRECTION;
    data->state = TIMESYNC_INITIALIZING;
+   data->slewState = TimeSyncUncalibrated;
    data->timeSyncPeriod = TIMESYNC_TIME;
    data->timer = NULL;
 
index e44c9c8a7058336e4b8a55741c4e3223014589fe..e0d3a6916a3117a39c388f26f8e61817a7fc6f2e 100644 (file)
@@ -37,11 +37,21 @@ Bool
 TimeSync_AddToCurrentTime(int64 delta);
 
 Bool
-TimeSync_EnableTimeSlew(int64 delta,
-                        int64 timeSyncPeriod);
+TimeSync_Slew(int64 delta,
+              int64 timeSyncPeriod,
+              int64 *remaining);
 
 Bool
 TimeSync_DisableTimeSlew(void);
 
+Bool
+TimeSync_PLLUpdate(int64 offset);
+
+Bool
+TimeSync_PLLSetFrequency(int64 ppmCorrection);
+
+Bool
+TimeSync_PLLSupported(void);
+
 #endif /* _TIMESYNC_INT_H_ */