diff --git a/chrony_timex.h b/chrony_timex.h index e262ff6..287d219 100644 --- a/chrony_timex.h +++ b/chrony_timex.h @@ -38,6 +38,7 @@ struct timex { #define ADJ_OFFSET 0x0001 /* time offset */ #define ADJ_FREQUENCY 0x0002 /* frequency offset */ #define ADJ_MAXERROR 0x0004 /* maximum time error */ +#define ADJ_ESTERROR 0x0008 /* estimated time error */ #define ADJ_STATUS 0x0010 /* clock status */ #define ADJ_TIMECONST 0x0020 /* pll time constant */ #define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */ diff --git a/sys_generic.c b/sys_generic.c index 3cdb184..44cb251 100644 --- a/sys_generic.c +++ b/sys_generic.c @@ -39,9 +39,10 @@ /* ================================================== */ -/* System clock frequency drivers */ +/* System clock drivers */ static lcl_ReadFrequencyDriver drv_read_freq; static lcl_SetFrequencyDriver drv_set_freq; +static lcl_SetSyncStatusDriver drv_set_sync_status; /* Current frequency as requested by the local module (in ppm) */ static double base_freq; @@ -270,6 +271,22 @@ apply_step_offset(double offset) /* ================================================== */ +static void +set_sync_status(int synchronised, double est_error, double max_error) +{ + double offset; + + offset = fabs(offset_register); + if (est_error < offset) + est_error = offset; + max_error += offset; + + if (drv_set_sync_status) + drv_set_sync_status(synchronised, est_error, max_error); +} + +/* ================================================== */ + void SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay, lcl_ReadFrequencyDriver sys_read_freq, @@ -282,6 +299,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6); drv_read_freq = sys_read_freq; drv_set_freq = sys_set_freq; + drv_set_sync_status = sys_set_sync_status; base_freq = (*drv_read_freq)(); slew_freq = 0.0; @@ -292,7 +310,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset, sys_apply_step_offset ? sys_apply_step_offset : apply_step_offset, - offset_convert, sys_set_leap, NULL); + offset_convert, sys_set_leap, set_sync_status); LCL_AddParameterChangeHandler(handle_step, NULL); } diff --git a/sys_linux.c b/sys_linux.c index 4e25751..d03eb2f 100644 --- a/sys_linux.c +++ b/sys_linux.c @@ -58,6 +58,9 @@ int LockAll = 0; #include "logging.h" #include "wrap_adjtimex.h" +/* The threshold for adjtimex maxerror when the kernel sets the UNSYNC flag */ +#define UNSYNC_MAXERROR 16.0 + /* This is the uncompensated system tick value */ static int nominal_tick; @@ -181,6 +184,29 @@ set_leap(int leap) /* ================================================== */ +static void +set_sync_status(int synchronised, double est_error, double max_error) +{ + if (synchronised) { + if (est_error > UNSYNC_MAXERROR) + est_error = UNSYNC_MAXERROR; + if (max_error >= UNSYNC_MAXERROR) { + max_error = UNSYNC_MAXERROR; + synchronised = 0; + } + } else { + est_error = max_error = UNSYNC_MAXERROR; + } + + /* Clear the UNSYNC flag only if rtcsync is enabled */ + if (!CNF_GetRtcSync()) + synchronised = 0; + + TMX_SetSync(synchronised, est_error, max_error); +} + +/* ================================================== */ + /* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when * it starts. The only credible values are 100 (Linux/x86) or powers of 2. * Also, the bounds checking inside the kernel's adjtimex system call enforces @@ -334,13 +360,11 @@ SYS_Linux_Initialise(void) have_setoffset = 0; } - TMX_SetSync(CNF_GetRtcSync()); - SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick, 1.0 / tick_update_hz, read_frequency, set_frequency, have_setoffset ? apply_step_offset : NULL, - set_leap, NULL); + set_leap, set_sync_status); } /* ================================================== */ diff --git a/wrap_adjtimex.c b/wrap_adjtimex.c index 8172c5f..a907ff8 100644 --- a/wrap_adjtimex.c +++ b/wrap_adjtimex.c @@ -68,19 +68,11 @@ TMX_SetFrequency(double *freq, long tick) { struct timex txc; - txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS; + txc.modes = ADJ_TICK | ADJ_FREQUENCY; txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC)); *freq = txc.freq / (double)(1 << SHIFT_USEC); txc.tick = tick; - txc.status = status; - - if (!(status & STA_UNSYNC)) { - /* maxerror has to be reset periodically to prevent kernel - from enabling UNSYNC flag */ - txc.modes |= ADJ_MAXERROR; - txc.maxerror = 0; - } return adjtimex(&txc); } @@ -161,7 +153,7 @@ TMX_SetLeap(int leap) return adjtimex(&txc); } -int TMX_SetSync(int sync) +int TMX_SetSync(int sync, double est_error, double max_error) { struct timex txc; @@ -171,8 +163,10 @@ int TMX_SetSync(int sync) status |= STA_UNSYNC; } - txc.modes = ADJ_STATUS; + txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR; txc.status = status; + txc.esterror = est_error * 1.0e6; + txc.maxerror = max_error * 1.0e6; return adjtimex(&txc); } diff --git a/wrap_adjtimex.h b/wrap_adjtimex.h index e7913b7..4e2bcf4 100644 --- a/wrap_adjtimex.h +++ b/wrap_adjtimex.h @@ -69,7 +69,7 @@ int TMX_SetFrequency(double *freq, long tick); int TMX_GetFrequency(double *freq, long *tick); int TMX_ReadCurrentParams(struct tmx_params *params); int TMX_SetLeap(int leap); -int TMX_SetSync(int sync); +int TMX_SetSync(int sync, double est_error, double max_error); int TMX_TestStepOffset(void); int TMX_ApplyStepOffset(double offset);