/* ================================================== */
+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)
{
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);
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;
/* ================================================== */
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;
}
/* ================================================== */
/* ================================================== */
+/* 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);
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 {