/* 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;
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();
+ }
}
/* ================================================== */
/* ================================================== */
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;
}
/* ================================================== */
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);
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);
}
/* 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
{
/* 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;
{
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;
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);
+}
extern void SMT_Reset(struct timeval *now);
+extern void SMT_Leap(struct timeval *now, int leap);
+
#endif
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
-
-run_test || test_fail
-check_chronyd_exit || test_fail
-check_source_selection || test_fail
-check_packet_interval || test_fail
-check_sync || test_fail
+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
+done
test_pass