Try to handle unexpected backward time jumps

This commit is contained in:
Miroslav Lichvar 2011-06-10 18:29:41 +02:00
parent 4ba3dd66ad
commit 91749ebb2b
3 changed files with 68 additions and 7 deletions

16
local.c
View file

@ -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 void
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset) LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
{ {

View file

@ -151,6 +151,11 @@ extern void LCL_AccumulateOffset(double offset);
extern void LCL_ApplyStepOffset(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 /* Perform the combination of modifying the frequency and applying
a slew, in one easy step */ a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset); extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset);

54
sched.c
View file

@ -70,9 +70,9 @@ typedef struct {
static FileHandlerEntry file_handlers[FD_SET_SIZE]; static FileHandlerEntry file_handlers[FD_SET_SIZE];
/* Last timestamp when a file descriptor became readable */ /* Timestamp when last select() returned */
static struct timeval last_fdready; static struct timeval last_select_ts, last_select_ts_raw;
static double last_fdready_err; static double last_select_ts_err;
/* ================================================== */ /* ================================================== */
@ -229,9 +229,9 @@ SCH_RemoveInputFileHandler(int fd)
void void
SCH_GetFileReadyTime(struct timeval *tv, double *err) SCH_GetFileReadyTime(struct timeval *tv, double *err)
{ {
*tv = last_fdready; *tv = last_select_ts;
if (err) 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 void
SCH_MainLoop(void) SCH_MainLoop(void)
{ {
fd_set rd; fd_set rd;
int status; int status;
struct timeval tv, *ptv; struct timeval tv, *ptv;
struct timeval now; struct timeval now, cooked;
double err;
assert(initialised); assert(initialised);
@ -557,12 +586,23 @@ SCH_MainLoop(void)
status = select(one_highest_fd, &rd, NULL, NULL, ptv); 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) { if (status < 0) {
assert(need_to_exit); assert(need_to_exit);
} else if (status > 0) { } else if (status > 0) {
/* A file descriptor is ready to read */ /* A file descriptor is ready to read */
LCL_ReadCookedTime(&last_fdready, &last_fdready_err);
dispatch_filehandlers(status, &rd); dispatch_filehandlers(status, &rd);
} else { } else {