reference: add new leap second handling modes
In addition to the system driver handling add new modes to slew or step the system clock for leap second, or ignore it completely. This can be configured with leapsecmode directive.
This commit is contained in:
parent
c68a92ba80
commit
f8db832491
6 changed files with 172 additions and 13 deletions
31
conf.c
31
conf.c
|
@ -63,6 +63,7 @@ static void parse_deny(char *);
|
|||
static void parse_fallbackdrift(char *);
|
||||
static void parse_include(char *);
|
||||
static void parse_initstepslew(char *);
|
||||
static void parse_leapsecmode(char *);
|
||||
static void parse_local(char *);
|
||||
static void parse_log(char *);
|
||||
static void parse_mailonchange(char *);
|
||||
|
@ -193,6 +194,9 @@ static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
|
|||
static int sched_priority = 0;
|
||||
static int lock_memory = 0;
|
||||
|
||||
/* Leap second handling mode */
|
||||
static REF_LeapMode leapsec_mode = REF_LeapModeSystem;
|
||||
|
||||
/* Name of a system timezone containing leap seconds occuring at midnight */
|
||||
static char *leapsec_tz = NULL;
|
||||
|
||||
|
@ -440,6 +444,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
|||
parse_initstepslew(p);
|
||||
} else if (!strcasecmp(command, "keyfile")) {
|
||||
parse_string(p, &keys_file);
|
||||
} else if (!strcasecmp(command, "leapsecmode")) {
|
||||
parse_leapsecmode(p);
|
||||
} else if (!strcasecmp(command, "leapsectz")) {
|
||||
parse_string(p, &leapsec_tz);
|
||||
} else if (!strcasecmp(command, "linux_freq_scale")) {
|
||||
|
@ -830,6 +836,23 @@ parse_initstepslew(char *line)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_leapsecmode(char *line)
|
||||
{
|
||||
if (!strcasecmp(line, "system"))
|
||||
leapsec_mode = REF_LeapModeSystem;
|
||||
else if (!strcasecmp(line, "slew"))
|
||||
leapsec_mode = REF_LeapModeSlew;
|
||||
else if (!strcasecmp(line, "step"))
|
||||
leapsec_mode = REF_LeapModeStep;
|
||||
else if (!strcasecmp(line, "ignore"))
|
||||
leapsec_mode = REF_LeapModeIgnore;
|
||||
else
|
||||
command_parse_error();
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_clientloglimit(char *line)
|
||||
{
|
||||
|
@ -1664,6 +1687,14 @@ CNF_GetPidFile(void)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
REF_LeapMode
|
||||
CNF_GetLeapSecMode(void)
|
||||
{
|
||||
return leapsec_mode;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetLeapSecTimezone(void)
|
||||
{
|
||||
|
|
2
conf.h
2
conf.h
|
@ -29,6 +29,7 @@
|
|||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "reference.h"
|
||||
|
||||
extern void CNF_Initialise(int restarted);
|
||||
extern void CNF_Finalise(void);
|
||||
|
@ -75,6 +76,7 @@ extern void CNF_GetBindAddress(int family, IPAddr *addr);
|
|||
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
|
||||
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
|
||||
extern char *CNF_GetPidFile(void);
|
||||
extern REF_LeapMode CNF_GetLeapSecMode(void);
|
||||
extern char *CNF_GetLeapSecTimezone(void);
|
||||
|
||||
/* Value returned in ppm, as read from file */
|
||||
|
|
16
local.c
16
local.c
|
@ -506,6 +506,20 @@ LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_NotifyLeap(int leap)
|
||||
{
|
||||
struct timeval raw, cooked;
|
||||
|
||||
LCL_ReadRawTime(&raw);
|
||||
LCL_CookTime(&raw, &cooked, NULL);
|
||||
|
||||
/* Dispatch to all handlers as if the clock was stepped */
|
||||
invoke_parameter_change_handlers(&raw, &cooked, 0.0, -leap, LCL_ChangeStep);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
|
||||
{
|
||||
|
@ -599,7 +613,7 @@ LCL_MakeStep(void)
|
|||
/* ================================================== */
|
||||
|
||||
void
|
||||
LCL_SetLeap(int leap)
|
||||
LCL_SetSystemLeap(int leap)
|
||||
{
|
||||
if (drv_set_leap) {
|
||||
(drv_set_leap)(leap);
|
||||
|
|
12
local.h
12
local.h
|
@ -166,6 +166,10 @@ extern void LCL_ApplyStepOffset(double offset);
|
|||
extern void LCL_NotifyExternalTimeStep(struct timeval *raw, struct timeval *cooked,
|
||||
double offset, double dispersion);
|
||||
|
||||
/* Routine to invoke notify handlers on leap second when the system clock
|
||||
doesn't correct itself */
|
||||
extern void LCL_NotifyLeap(int leap);
|
||||
|
||||
/* Perform the combination of modifying the frequency and applying
|
||||
a slew, in one easy step */
|
||||
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
|
||||
|
@ -194,10 +198,10 @@ extern void LCL_Finalise(void);
|
|||
to a timezone problem. */
|
||||
extern int LCL_MakeStep(void);
|
||||
|
||||
/* Routine to schedule a leap second. Leap second will be inserted
|
||||
at the end of the day if argument is positive, deleted if negative,
|
||||
and zero cancels scheduled leap second. */
|
||||
extern void LCL_SetLeap(int leap);
|
||||
/* Routine to set the system clock to correct itself for a leap second if
|
||||
supported. Leap second will be inserted at the end of the day if the
|
||||
argument is positive, deleted if negative, and zero resets the setting. */
|
||||
extern void LCL_SetSystemLeap(int leap);
|
||||
|
||||
/* Routine to set a frequency correction (in ppm) that should be applied
|
||||
to local clock to compensate for temperature changes. A positive
|
||||
|
|
116
reference.c
116
reference.c
|
@ -98,6 +98,17 @@ static double drift_file_age;
|
|||
|
||||
static void update_drift_file(double, double);
|
||||
|
||||
/* Leap second handling mode */
|
||||
static REF_LeapMode leap_mode;
|
||||
|
||||
/* Flag indicating the clock was recently corrected for leap second and it may
|
||||
not have correct time yet (missing 23:59:60 in the UTC time scale) */
|
||||
static int leap_in_progress;
|
||||
|
||||
/* Timer for the leap second handler */
|
||||
static int leap_timer_running;
|
||||
static SCH_TimeoutID leap_timeout_id;
|
||||
|
||||
/* Name of a system timezone containing leap seconds occuring at midnight */
|
||||
static char *leap_tzname;
|
||||
static time_t last_tz_leap_check;
|
||||
|
@ -136,6 +147,7 @@ static double last_ref_update_interval;
|
|||
/* ================================================== */
|
||||
|
||||
static NTP_Leap get_tz_leap(time_t when);
|
||||
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
@ -148,6 +160,7 @@ handle_slew(struct timeval *raw,
|
|||
void *anything)
|
||||
{
|
||||
double delta;
|
||||
struct timeval now;
|
||||
|
||||
if (change_type == LCL_ChangeUnknownStep) {
|
||||
last_ref_update.tv_sec = 0;
|
||||
|
@ -155,6 +168,13 @@ handle_slew(struct timeval *raw,
|
|||
} else if (last_ref_update.tv_sec) {
|
||||
UTI_AdjustTimeval(&last_ref_update, cooked, &last_ref_update, &delta, dfreq, doffset);
|
||||
}
|
||||
|
||||
/* When the clock was stepped, check if that doesn't change our leap status
|
||||
and also reset the leap timeout to undo the shift in the scheduler */
|
||||
if (change_type != LCL_ChangeAdjust && our_leap_sec && !leap_in_progress) {
|
||||
LCL_ReadRawTime(&now);
|
||||
update_leap_status(our_leap_status, now.tv_sec, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -217,6 +237,10 @@ REF_Initialise(void)
|
|||
|
||||
enable_local_stratum = CNF_AllowLocalReference(&local_stratum);
|
||||
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
leap_mode = CNF_GetLeapSecMode();
|
||||
|
||||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname) {
|
||||
/* Check that the timezone has good data for Jun 30 2008 and Dec 31 2008 */
|
||||
|
@ -263,9 +287,7 @@ REF_Initialise(void)
|
|||
void
|
||||
REF_Finalise(void)
|
||||
{
|
||||
if (our_leap_sec) {
|
||||
LCL_SetLeap(0);
|
||||
}
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
|
||||
if (drift_file) {
|
||||
update_drift_file(LCL_ReadAbsoluteFrequency(), our_skew);
|
||||
|
@ -657,7 +679,72 @@ get_tz_leap(time_t when)
|
|||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now)
|
||||
leap_end_timeout(void *arg)
|
||||
{
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
leap_start_timeout(void *arg)
|
||||
{
|
||||
leap_in_progress = 1;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSlew:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_AccumulateOffset(our_leap_sec, 0.0);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Adjusting system clock for leap second");
|
||||
break;
|
||||
case REF_LeapModeStep:
|
||||
LCL_NotifyLeap(our_leap_sec);
|
||||
LCL_ApplyStepOffset(our_leap_sec);
|
||||
LOG(LOGS_WARN, LOGF_Reference, "System clock was stepped for leap second");
|
||||
break;
|
||||
case REF_LeapModeIgnore:
|
||||
LOG(LOGS_WARN, LOGF_Reference, "Ignoring leap second");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait until the leap second is over with some extra room to be safe */
|
||||
leap_timeout_id = SCH_AddTimeoutByDelay(2.0, leap_end_timeout, NULL);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
set_leap_timeout(time_t now)
|
||||
{
|
||||
struct timeval when;
|
||||
|
||||
/* Stop old timer if there is one */
|
||||
if (leap_timer_running) {
|
||||
SCH_RemoveTimeout(leap_timeout_id);
|
||||
leap_timer_running = 0;
|
||||
leap_in_progress = 0;
|
||||
}
|
||||
|
||||
if (!our_leap_sec)
|
||||
return;
|
||||
|
||||
/* Insert leap second at 0:00:00 UTC, delete at 23:59:59 UTC */
|
||||
when.tv_sec = (now / (24 * 3600) + 1) * (24 * 3600);
|
||||
when.tv_usec = 0;
|
||||
if (our_leap_sec < 0)
|
||||
when.tv_sec--;
|
||||
|
||||
leap_timeout_id = SCH_AddTimeout(&when, leap_start_timeout, NULL);
|
||||
leap_timer_running = 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
{
|
||||
int leap_sec;
|
||||
|
||||
|
@ -680,9 +767,22 @@ update_leap_status(NTP_Leap leap, time_t now)
|
|||
}
|
||||
}
|
||||
|
||||
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
|
||||
LCL_SetLeap(leap_sec);
|
||||
if (reset || (leap_sec != our_leap_sec && !REF_IsLeapSecondClose())) {
|
||||
our_leap_sec = leap_sec;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
LCL_SetSystemLeap(our_leap_sec);
|
||||
break;
|
||||
case REF_LeapModeSlew:
|
||||
case REF_LeapModeStep:
|
||||
case REF_LeapModeIgnore:
|
||||
set_leap_timeout(now);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
our_leap_status = leap;
|
||||
|
@ -920,7 +1020,7 @@ REF_SetReference(int stratum,
|
|||
our_residual_freq = frequency;
|
||||
}
|
||||
|
||||
update_leap_status(leap, raw_now.tv_sec);
|
||||
update_leap_status(leap, raw_now.tv_sec, 0);
|
||||
maybe_log_offset(our_offset, raw_now.tv_sec);
|
||||
|
||||
if (step_offset != 0.0) {
|
||||
|
@ -1015,7 +1115,7 @@ REF_SetUnsynchronised(void)
|
|||
schedule_fb_drift(&now);
|
||||
}
|
||||
|
||||
update_leap_status(LEAP_Unsynchronised, 0);
|
||||
update_leap_status(LEAP_Unsynchronised, 0, 0);
|
||||
are_we_synchronised = 0;
|
||||
|
||||
LCL_SetSyncStatus(0, 0.0, 0.0);
|
||||
|
|
|
@ -35,6 +35,14 @@
|
|||
#include "ntp.h"
|
||||
#include "reports.h"
|
||||
|
||||
/* Leap second handling modes */
|
||||
typedef enum {
|
||||
REF_LeapModeSystem,
|
||||
REF_LeapModeSlew,
|
||||
REF_LeapModeStep,
|
||||
REF_LeapModeIgnore,
|
||||
} REF_LeapMode;
|
||||
|
||||
/* Init function */
|
||||
extern void REF_Initialise(void);
|
||||
|
||||
|
|
Loading…
Reference in a new issue