sched: improve time jump detection
To detect forward time jumps, use a timestamp made before calling select() instead of the first timeout in the queue. Also, if the timeout value is modified by select() (e.g. on Linux) use it to get a more accurate estimate of the elapsed time.
This commit is contained in:
parent
badf97d4ba
commit
e63bd490b0
1 changed files with 38 additions and 15 deletions
53
sched.c
53
sched.c
|
@ -539,28 +539,49 @@ handle_slew(struct timeval *raw,
|
||||||
#define JUMP_DETECT_THRESHOLD 10
|
#define JUMP_DETECT_THRESHOLD 10
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_current_time(struct timeval *raw, int timeout)
|
check_current_time(struct timeval *prev_raw, struct timeval *raw, int timeout,
|
||||||
|
struct timeval *orig_select_tv,
|
||||||
|
struct timeval *rem_select_tv)
|
||||||
{
|
{
|
||||||
double diff;
|
struct timeval elapsed_min, elapsed_max;
|
||||||
|
double step, elapsed;
|
||||||
|
|
||||||
if (last_select_ts_raw.tv_sec > raw->tv_sec + JUMP_DETECT_THRESHOLD) {
|
/* Get an estimate of the time spent waiting in the select() call. On some
|
||||||
|
systems (e.g. Linux) the timeout timeval is modified to return the
|
||||||
|
remaining time, use that information. */
|
||||||
|
if (timeout) {
|
||||||
|
elapsed_max = elapsed_min = *orig_select_tv;
|
||||||
|
} else if (rem_select_tv && rem_select_tv->tv_sec >= 0 &&
|
||||||
|
rem_select_tv->tv_sec <= orig_select_tv->tv_sec &&
|
||||||
|
(rem_select_tv->tv_sec != orig_select_tv->tv_sec ||
|
||||||
|
rem_select_tv->tv_usec != orig_select_tv->tv_usec)) {
|
||||||
|
UTI_DiffTimevals(&elapsed_min, orig_select_tv, rem_select_tv);
|
||||||
|
elapsed_max = elapsed_min;
|
||||||
|
} else {
|
||||||
|
if (rem_select_tv)
|
||||||
|
elapsed_max = *orig_select_tv;
|
||||||
|
else
|
||||||
|
UTI_DiffTimevals(&elapsed_max, raw, prev_raw);
|
||||||
|
elapsed_min.tv_sec = 0;
|
||||||
|
elapsed_min.tv_usec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_select_ts_raw.tv_sec + elapsed_min.tv_sec >
|
||||||
|
raw->tv_sec + JUMP_DETECT_THRESHOLD) {
|
||||||
LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected!");
|
LOG(LOGS_WARN, LOGF_Scheduler, "Backward time jump detected!");
|
||||||
} else if (n_timer_queue_entries > 0 &&
|
} else if (prev_raw->tv_sec + elapsed_max.tv_sec + JUMP_DETECT_THRESHOLD <
|
||||||
timer_queue.next->tv.tv_sec + JUMP_DETECT_THRESHOLD < raw->tv_sec) {
|
raw->tv_sec) {
|
||||||
LOG(LOGS_WARN, LOGF_Scheduler, "Forward time jump detected!");
|
LOG(LOGS_WARN, LOGF_Scheduler, "Forward time jump detected!");
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout) {
|
UTI_DiffTimevalsToDouble(&step, &last_select_ts_raw, raw);
|
||||||
assert(n_timer_queue_entries > 0);
|
UTI_TimevalToDouble(&elapsed_min, &elapsed);
|
||||||
UTI_DiffTimevalsToDouble(&diff, &timer_queue.next->tv, raw);
|
step += elapsed;
|
||||||
} else {
|
|
||||||
UTI_DiffTimevalsToDouble(&diff, &last_select_ts_raw, raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cooked time may no longer be valid after dispatching the handlers */
|
/* Cooked time may no longer be valid after dispatching the handlers */
|
||||||
LCL_NotifyExternalTimeStep(raw, raw, diff, fabs(diff));
|
LCL_NotifyExternalTimeStep(raw, raw, step, fabs(step));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -572,8 +593,8 @@ SCH_MainLoop(void)
|
||||||
{
|
{
|
||||||
fd_set rd;
|
fd_set rd;
|
||||||
int status, errsv;
|
int status, errsv;
|
||||||
struct timeval tv, *ptv;
|
struct timeval tv, saved_tv, *ptv;
|
||||||
struct timeval now, cooked;
|
struct timeval now, saved_now, cooked;
|
||||||
double err;
|
double err;
|
||||||
|
|
||||||
assert(initialised);
|
assert(initialised);
|
||||||
|
@ -581,6 +602,7 @@ SCH_MainLoop(void)
|
||||||
while (!need_to_exit) {
|
while (!need_to_exit) {
|
||||||
/* Dispatch timeouts and fill now with current raw time */
|
/* Dispatch timeouts and fill now with current raw time */
|
||||||
dispatch_timeouts(&now);
|
dispatch_timeouts(&now);
|
||||||
|
saved_now = now;
|
||||||
|
|
||||||
/* The timeout handlers may request quit */
|
/* The timeout handlers may request quit */
|
||||||
if (need_to_exit)
|
if (need_to_exit)
|
||||||
|
@ -592,6 +614,7 @@ SCH_MainLoop(void)
|
||||||
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
|
UTI_DiffTimevals(&tv, &(timer_queue.next->tv), &now);
|
||||||
ptv = &tv;
|
ptv = &tv;
|
||||||
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
|
assert(tv.tv_sec > 0 || tv.tv_usec > 0);
|
||||||
|
saved_tv = tv;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ptv = NULL;
|
ptv = NULL;
|
||||||
|
@ -613,7 +636,7 @@ SCH_MainLoop(void)
|
||||||
LCL_CookTime(&now, &cooked, &err);
|
LCL_CookTime(&now, &cooked, &err);
|
||||||
|
|
||||||
/* Check if the time didn't jump unexpectedly */
|
/* Check if the time didn't jump unexpectedly */
|
||||||
if (!check_current_time(&now, status == 0)) {
|
if (!check_current_time(&saved_now, &now, status == 0, &saved_tv, ptv)) {
|
||||||
/* Cook the time again after handling the step */
|
/* Cook the time again after handling the step */
|
||||||
LCL_CookTime(&now, &cooked, &err);
|
LCL_CookTime(&now, &cooked, &err);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue