]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
sys_netbsd: add fast slewing based on adjtime()
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 22 Sep 2015 15:18:43 +0000 (17:18 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Wed, 23 Sep 2015 09:19:34 +0000 (11:19 +0200)
Implement slewing based on adjtime() that the generic driver can use to
correct offsets larger than 1 second with 5000 ppm slewing rate.

sys_netbsd.c

index 7abc562333513b23a02eb3e8f811170977111bc0..36222de3c01cb06566ed85bff367bb645f5bd5c7 100644 (file)
 #include "sys_netbsd.h"
 #include "sys_timex.h"
 #include "logging.h"
+#include "util.h"
+
+/* Maximum frequency offset accepted by the kernel (in ppm) */
+#define MAX_FREQ 500.0
+
+/* Minimum assumed rate at which the kernel updates the clock frequency */
+#define MIN_TICK_RATE 100
+
+/* Interval between kernel updates of the adjtime() offset */
+#define ADJTIME_UPDATE_INTERVAL 1.0
+
+/* Maximum adjtime() slew rate (in ppm) */
+#define MAX_ADJTIME_SLEWRATE 5000.0
+
+/* Minimum offset adjtime() slews faster than MAX_FREQ */
+#define MIN_FASTSLEW_OFFSET 1.0
+
+/* ================================================== */
+
+/* Positive offset means system clock is fast of true time, therefore
+   slew backwards */
+
+static void
+accrue_offset(double offset, double corr_rate)
+{
+  struct timeval newadj, oldadj;
+
+  UTI_DoubleToTimeval(-offset, &newadj);
+
+  if (adjtime(&newadj, &oldadj) < 0)
+    LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+
+  /* Add the old remaining adjustment if not zero */
+  UTI_TimevalToDouble(&oldadj, &offset);
+  if (offset != 0.0) {
+    UTI_AddDoubleToTimeval(&newadj, offset, &newadj);
+    if (adjtime(&newadj, NULL) < 0)
+      LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+  }
+}
+
+/* ================================================== */
+
+static void
+get_offset_correction(struct timeval *raw,
+                      double *corr, double *err)
+{
+  struct timeval remadj;
+  double adjustment_remaining;
+
+  if (adjtime(NULL, &remadj) < 0)
+    LOG_FATAL(LOGF_SysNetBSD, "adjtime() failed");
+
+  UTI_TimevalToDouble(&remadj, &adjustment_remaining);
+
+  *corr = adjustment_remaining;
+  if (err) {
+    if (*corr != 0.0)
+      *err = 1.0e-6 * MAX_ADJTIME_SLEWRATE / ADJTIME_UPDATE_INTERVAL;
+    else
+      *err = 0.0;
+  }
+}
 
 /* ================================================== */
 
 void
 SYS_NetBSD_Initialise(void)
 {
-  SYS_Timex_Initialise();
+  SYS_Timex_InitialiseWithFunctions(MAX_FREQ, 1.0 / MIN_TICK_RATE,
+                                    NULL, NULL, NULL,
+                                    MIN_FASTSLEW_OFFSET, MAX_ADJTIME_SLEWRATE,
+                                    accrue_offset, get_offset_correction);
 }
 
 /* ================================================== */