diff --git a/conf.c b/conf.c index 513633f..a83d937 100644 --- a/conf.c +++ b/conf.c @@ -189,6 +189,7 @@ static char *pidfile; /* Smoothing constants */ static double smooth_max_freq = 0.0; /* in ppm */ static double smooth_max_wander = 0.0; /* in ppm/s */ +static int smooth_leap_only = 0; /* Temperature sensor, update interval and compensation coefficients */ static char *tempcomp_sensor_file = NULL; @@ -1174,11 +1175,23 @@ parse_broadcast(char *line) static void parse_smoothtime(char *line) { - check_number_of_args(line, 2); + if (get_number_of_args(line) != 3) + check_number_of_args(line, 2); + if (sscanf(line, "%lf %lf", &smooth_max_freq, &smooth_max_wander) != 2) { smooth_max_freq = 0.0; command_parse_error(); } + + line = CPS_SplitWord(CPS_SplitWord(line)); + smooth_leap_only = 0; + + if (*line) { + if (!strcasecmp(line, "leaponly")) + smooth_leap_only = 1; + else + command_parse_error(); + } } /* ================================================== */ @@ -1738,10 +1751,11 @@ CNF_GetLockMemory(void) /* ================================================== */ void -CNF_GetSmooth(double *max_freq, double *max_wander) +CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only) { *max_freq = smooth_max_freq; *max_wander = smooth_max_wander; + *leap_only = smooth_leap_only; } /* ================================================== */ diff --git a/conf.h b/conf.h index 4d51d24..ec08ded 100644 --- a/conf.h +++ b/conf.h @@ -96,7 +96,7 @@ extern void CNF_SetupAccessRestrictions(void); extern int CNF_GetSchedPriority(void); extern int CNF_GetLockMemory(void); -extern void CNF_GetSmooth(double *max_freq, double *max_wander); +extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only); extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2); extern char *CNF_GetUser(void); diff --git a/local.c b/local.c index 53abf99..848cc3e 100644 --- a/local.c +++ b/local.c @@ -564,6 +564,9 @@ LCL_NotifyLeap(int leap) LCL_ReadRawTime(&raw); LCL_CookTime(&raw, &cooked, NULL); + /* Smooth the leap second out */ + SMT_Leap(&cooked, leap); + /* Dispatch to all handlers as if the clock was stepped */ invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep); } diff --git a/smooth.c b/smooth.c index dc145da..e5c60f4 100644 --- a/smooth.c +++ b/smooth.c @@ -77,6 +77,10 @@ static struct stage stages[NUM_STAGES]; /* Enabled/disabled smoothing */ static int enabled; +/* Enabled/disabled mode where only leap seconds are smoothed out and normal + offset/frequency changes are ignored */ +static int leap_only_mode; + /* Maximum skew/max_wander ratio to start updating offset and frequency */ #define UNLOCK_SKEW_WANDER_RATIO 10000 @@ -185,8 +189,9 @@ update_smoothing(struct timeval *now, double offset, double freq) { /* Don't accept offset/frequency until the clock has stabilized */ if (locked) { - if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO) { - LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated"); + if (REF_GetSkew() / max_wander < UNLOCK_SKEW_WANDER_RATIO || leap_only_mode) { + LOG(LOGS_INFO, LOGF_Smooth, "Time smoothing activated%s", leap_only_mode ? + " (leap seconds only)" : ""); locked = 0; } return; @@ -208,15 +213,19 @@ handle_slew(struct timeval *raw, struct timeval *cooked, double dfreq, { double delta; - if (change_type == LCL_ChangeAdjust) - update_smoothing(cooked, doffset, dfreq); + if (change_type == LCL_ChangeAdjust) { + if (leap_only_mode) + update_smoothing(cooked, 0.0, 0.0); + else + update_smoothing(cooked, doffset, dfreq); + } UTI_AdjustTimeval(&last_update, cooked, &last_update, &delta, dfreq, doffset); } void SMT_Initialise(void) { - CNF_GetSmooth(&max_freq, &max_wander); + CNF_GetSmooth(&max_freq, &max_wander, &leap_only_mode); if (max_freq <= 0.0 || max_wander <= 0.0) { enabled = 0; return; @@ -265,3 +274,14 @@ SMT_Reset(struct timeval *now) smooth_freq = 0.0; last_update = *now; } + +void +SMT_Leap(struct timeval *now, int leap) +{ + /* When the leap-only mode is disabled, the leap second will be accumulated + in handle_slew() as a normal offset */ + if (!enabled || !leap_only_mode) + return; + + update_smoothing(now, leap, 0.0); +} diff --git a/smooth.h b/smooth.h index c2877d6..4cb72d7 100644 --- a/smooth.h +++ b/smooth.h @@ -37,4 +37,6 @@ extern double SMT_GetOffset(struct timeval *now); extern void SMT_Reset(struct timeval *now); +extern void SMT_Leap(struct timeval *now, int leap); + #endif diff --git a/test/simulation/113-leapsecond b/test/simulation/113-leapsecond index af4b547..7d67007 100755 --- a/test/simulation/113-leapsecond +++ b/test/simulation/113-leapsecond @@ -27,18 +27,20 @@ for leapmode in system step slew; do check_sync || test_fail done -server_conf="refclock SHM 0 dpoll 10 poll 10 -leapsectz right/UTC -leapsecmode slew -smoothtime 400 0.001" -client_conf="leapsecmode system" -min_sync_time=230000 -max_sync_time=240000 +for smoothmode in "" "leaponly"; do + server_conf="refclock SHM 0 dpoll 10 poll 10 + leapsectz right/UTC + leapsecmode slew + smoothtime 400 0.001 $smoothmode" + client_conf="leapsecmode system" + min_sync_time=230000 + max_sync_time=240000 -run_test || test_fail -check_chronyd_exit || test_fail -check_source_selection || test_fail -check_packet_interval || test_fail -check_sync || test_fail + run_test || test_fail + check_chronyd_exit || test_fail + check_source_selection || test_fail + check_packet_interval || test_fail + check_sync || test_fail +done test_pass