]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
Try to handle unexpected backward time jumps
authorMiroslav Lichvar <mlichvar@redhat.com>
Fri, 10 Jun 2011 16:29:41 +0000 (18:29 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Fri, 10 Jun 2011 16:29:41 +0000 (18:29 +0200)
local.c
local.h
sched.c

diff --git a/local.c b/local.c
index 801751219d3f14889de8d9e49cd454b2c7d68f56..76196973554ef885f2013497a9fdd25a466d19b2 100644 (file)
--- a/local.c
+++ b/local.c
@@ -488,6 +488,22 @@ LCL_ApplyStepOffset(double offset)
 
 /* ================================================== */
 
+void
+LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
+    double offset, double dispersion)
+{
+  ChangeListEntry *ptr;
+
+  /* Dispatch to all handlers */
+  for (ptr = change_list.next; ptr != &change_list; ptr = ptr->next) {
+    (ptr->handler)(raw, cooked, 0.0, offset, 1, ptr->anything);
+  }
+
+  lcl_InvokeDispersionNotifyHandlers(dispersion);
+}
+
+/* ================================================== */
+
 void
 LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
 {
diff --git a/local.h b/local.h
index fd2a9154f175fcd433ca180df1c4e399d2db96c0..40c085363e4b31b0d284a621eb7090eb3b215b89 100644 (file)
--- a/local.h
+++ b/local.h
@@ -151,6 +151,11 @@ extern void LCL_AccumulateOffset(double offset);
 
 extern void LCL_ApplyStepOffset(double offset);
 
+/* Routine to invoke notify handlers on an unexpected time jump
+   in system clock */
+extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
+    double offset, double dispersion);
+
 /* Perform the combination of modifying the frequency and applying
    a slew, in one easy step */
 extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);
diff --git a/sched.c b/sched.c
index c70e195ab56f9d36748de3944e67e790c6727fd6..e5e4a5253082df7fb8f2b78e67c0b94f0eba896e 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -70,9 +70,9 @@ typedef struct {
 
 static FileHandlerEntry file_handlers[FD_SET_SIZE];
 
-/* Last timestamp when a file descriptor became readable */
-static struct timeval last_fdready;
-static double last_fdready_err;
+/* Timestamp when last select() returned */
+static struct timeval last_select_ts, last_select_ts_raw;
+static double last_select_ts_err;
 
 /* ================================================== */
 
@@ -229,9 +229,9 @@ SCH_RemoveInputFileHandler(int fd)
 void
 SCH_GetFileReadyTime(struct timeval *tv, double *err)
 {
-  *tv = last_fdready;
+  *tv = last_select_ts;
   if (err)
-    *err = last_fdready_err;
+    *err = last_select_ts_err;
 }
 
 /* ================================================== */
@@ -514,13 +514,42 @@ handle_slew(struct timeval *raw,
 
 /* ================================================== */
 
+/* Try to handle unexpected backward time jump */
+
+static void
+recover_backjump(struct timeval *raw, struct timeval *cooked, int timeout)
+{
+      double diff, err;
+
+      UTI_DiffTimevalsToDouble(&diff, &last_select_ts_raw, raw);
+
+      if (n_timer_queue_entries > 0) {
+        UTI_DiffTimevalsToDouble(&err, &(timer_queue.next->tv), &last_select_ts_raw);
+      } else {
+        err = 0.0;
+      }
+
+      diff += err;
+
+      if (timeout) {
+        err = 1.0;
+      }
+
+      LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected! (correction %.1f +- %.1f seconds)", diff, err);
+
+      LCL_NotifyExternalTimeStep(raw, cooked, diff, err);
+}
+
+/* ================================================== */
+
 void
 SCH_MainLoop(void)
 {
   fd_set rd;
   int status;
   struct timeval tv, *ptv;
-  struct timeval now;
+  struct timeval now, cooked;
+  double err;
 
   assert(initialised);
 
@@ -557,12 +586,23 @@ SCH_MainLoop(void)
 
     status = select(one_highest_fd, &rd, NULL, NULL, ptv);
 
+    LCL_ReadRawTime(&now);
+    LCL_CookTime(&now, &cooked, &err);
+
+    /* Check if time didn't jump backwards */
+    if (last_select_ts_raw.tv_sec > now.tv_sec + 1) {
+      recover_backjump(&now, &cooked, status == 0);
+    }
+
+    last_select_ts_raw = now;
+    last_select_ts = cooked;
+    last_select_ts_err = err;
+
     if (status < 0) {
       assert(need_to_exit);
     } else if (status > 0) {
       /* A file descriptor is ready to read */
 
-      LCL_ReadCookedTime(&last_fdready, &last_fdready_err);
       dispatch_filehandlers(status, &rd);
 
     } else {