reference: get TAI-UTC offset from leap second timezone
Use the timezone specified by the leapsectz directive to get the current TAI-UTC offset and set the offset of the system clock in order to provide correct TAI time to applications using ntp_adjtime(), ntp_gettime(), or clock_gettime(CLOCK_TAI).
This commit is contained in:
parent
cde0a20307
commit
29b0ad894c
2 changed files with 52 additions and 22 deletions
|
@ -830,15 +830,23 @@ clients to safely synchronise with multiple identically configured leap
|
|||
smearing servers.
|
||||
|
||||
[[leapsectz]]*leapsectz* _timezone_::
|
||||
This directive is used to set the name of the timezone in the system tz
|
||||
database which *chronyd* can use to find out when will the next leap second
|
||||
occur. It will periodically check if the times 23:59:59 and 23:59:60 are valid
|
||||
on Jun 30 and Dec 31 in the timezone. This typically works with the *right/UTC*
|
||||
timezone.
|
||||
This directive specifies a timezone in the system tz database which *chronyd*
|
||||
can use to determine when will the next leap second occur and what is the
|
||||
current offset between TAI and UTC. It will periodically check if 23:59:59 and
|
||||
23:59:60 are valid times in the timezone. This typically works with the
|
||||
_right/UTC_ timezone.
|
||||
+
|
||||
This directive is mainly useful with reference clocks which do not provide
|
||||
leap second information. It is not necessary to restart *chronyd* if the tz
|
||||
database is updated with a new leap second at least 12 hours before the event.
|
||||
When a leap second is announced, the timezone needs to be updated at least 12
|
||||
hours before the leap second. It is not necessary to restart *chronyd*.
|
||||
+
|
||||
This directive is useful with reference clocks and other time sources which do
|
||||
not announce leap seconds, or announce them too late for an NTP server to
|
||||
forward them to its own clients. Clients of leap smearing servers must not
|
||||
use this directive.
|
||||
+
|
||||
It is also useful when the system clock is required to have correct TAI-UTC
|
||||
offset. Note that the offset is set only when leap seconds are handled by the
|
||||
kernel, i.e. <<leapsecmode,*leapsecmode*>> is set to *system*.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
|
@ -2325,7 +2333,7 @@ The amount of memory used for logging client accesses can be increased in order
|
|||
to enable clients to use the interleaved mode even when the server has a large
|
||||
number of clients, and better support rate limiting if it is enabled by the
|
||||
<<ratelimit,*ratelimit*>> directive. The system timezone database, if it is
|
||||
kept up to date and includes the *right/UTC* timezone, can be used as a
|
||||
kept up to date and includes the _right/UTC_ timezone, can be used as a
|
||||
reliable source to determine when a leap second will be applied to UTC. The
|
||||
*-r* option with the <<dumpdir,*dumpdir*>> directive shortens the time in which
|
||||
*chronyd* will not be able to serve time to its clients when it needs to be
|
||||
|
|
48
reference.c
48
reference.c
|
@ -49,6 +49,7 @@ static int local_orphan;
|
|||
static double local_distance;
|
||||
static NTP_Leap our_leap_status;
|
||||
static int our_leap_sec;
|
||||
static int our_tai_offset;
|
||||
static int our_stratum;
|
||||
static uint32_t our_ref_id;
|
||||
static IPAddr our_ref_ip;
|
||||
|
@ -139,7 +140,7 @@ static double last_ref_update_interval;
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static NTP_Leap get_tz_leap(time_t when);
|
||||
static NTP_Leap get_tz_leap(time_t when, int *tai_offset);
|
||||
static void update_leap_status(NTP_Leap leap, time_t now, int reset);
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -179,11 +180,13 @@ REF_Initialise(void)
|
|||
FILE *in;
|
||||
double file_freq_ppm, file_skew_ppm;
|
||||
double our_frequency_ppm;
|
||||
int tai_offset;
|
||||
|
||||
mode = REF_ModeNormal;
|
||||
are_we_synchronised = 0;
|
||||
our_leap_status = LEAP_Unsynchronised;
|
||||
our_leap_sec = 0;
|
||||
our_tai_offset = 0;
|
||||
initialised = 1;
|
||||
our_root_dispersion = 1.0;
|
||||
our_root_delay = 1.0;
|
||||
|
@ -241,8 +244,8 @@ REF_Initialise(void)
|
|||
leap_tzname = CNF_GetLeapSecTimezone();
|
||||
if (leap_tzname) {
|
||||
/* Check that the timezone has good data for Jun 30 2012 and Dec 31 2012 */
|
||||
if (get_tz_leap(1341014400) == LEAP_InsertSecond &&
|
||||
get_tz_leap(1356912000) == LEAP_Normal) {
|
||||
if (get_tz_leap(1341014400, &tai_offset) == LEAP_InsertSecond && tai_offset == 34 &&
|
||||
get_tz_leap(1356912000, &tai_offset) == LEAP_Normal && tai_offset == 35) {
|
||||
LOG(LOGS_INFO, "Using %s timezone to obtain leap second data", leap_tzname);
|
||||
} else {
|
||||
LOG(LOGS_WARN, "Timezone %s failed leap second check, ignoring", leap_tzname);
|
||||
|
@ -613,14 +616,18 @@ is_leap_second_day(struct tm *stm) {
|
|||
/* ================================================== */
|
||||
|
||||
static NTP_Leap
|
||||
get_tz_leap(time_t when)
|
||||
get_tz_leap(time_t when, int *tai_offset)
|
||||
{
|
||||
static time_t last_tz_leap_check;
|
||||
static NTP_Leap tz_leap;
|
||||
static int tz_tai_offset;
|
||||
|
||||
struct tm stm;
|
||||
time_t t;
|
||||
char *tz_env, tz_orig[128];
|
||||
|
||||
*tai_offset = tz_tai_offset;
|
||||
|
||||
/* Do this check at most twice a day */
|
||||
when = when / (12 * 3600) * (12 * 3600);
|
||||
if (last_tz_leap_check == when)
|
||||
|
@ -628,12 +635,10 @@ get_tz_leap(time_t when)
|
|||
|
||||
last_tz_leap_check = when;
|
||||
tz_leap = LEAP_Normal;
|
||||
tz_tai_offset = 0;
|
||||
|
||||
stm = *gmtime(&when);
|
||||
|
||||
if (!is_leap_second_day(&stm))
|
||||
return tz_leap;
|
||||
|
||||
/* Temporarily switch to the timezone containing leap seconds */
|
||||
tz_env = getenv("TZ");
|
||||
if (tz_env) {
|
||||
|
@ -644,6 +649,11 @@ get_tz_leap(time_t when)
|
|||
setenv("TZ", leap_tzname, 1);
|
||||
tzset();
|
||||
|
||||
/* Get the TAI-UTC offset, which started at the epoch at 10 seconds */
|
||||
t = mktime(&stm);
|
||||
if (t != -1)
|
||||
tz_tai_offset = t - when + 10;
|
||||
|
||||
/* Set the time to 23:59:60 and see how it overflows in mktime() */
|
||||
stm.tm_sec = 60;
|
||||
stm.tm_min = 59;
|
||||
|
@ -665,6 +675,8 @@ get_tz_leap(time_t when)
|
|||
else if (stm.tm_sec == 1)
|
||||
tz_leap = LEAP_DeleteSecond;
|
||||
|
||||
*tai_offset = tz_tai_offset;
|
||||
|
||||
return tz_leap;
|
||||
}
|
||||
|
||||
|
@ -675,10 +687,13 @@ leap_end_timeout(void *arg)
|
|||
{
|
||||
leap_timeout_id = 0;
|
||||
leap_in_progress = 0;
|
||||
|
||||
if (our_tai_offset)
|
||||
our_tai_offset += our_leap_sec;
|
||||
our_leap_sec = 0;
|
||||
|
||||
if (leap_mode == REF_LeapModeSystem)
|
||||
LCL_SetSystemLeap(our_leap_sec, 0);
|
||||
LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
|
||||
|
||||
if (our_leap_status == LEAP_InsertSecond ||
|
||||
our_leap_status == LEAP_DeleteSecond)
|
||||
|
@ -752,12 +767,17 @@ set_leap_timeout(time_t now)
|
|||
static void
|
||||
update_leap_status(NTP_Leap leap, time_t now, int reset)
|
||||
{
|
||||
int leap_sec;
|
||||
NTP_Leap tz_leap;
|
||||
int leap_sec, tai_offset;
|
||||
|
||||
leap_sec = 0;
|
||||
tai_offset = 0;
|
||||
|
||||
if (leap_tzname && now && leap == LEAP_Normal)
|
||||
leap = get_tz_leap(now);
|
||||
if (leap_tzname && now) {
|
||||
tz_leap = get_tz_leap(now, &tai_offset);
|
||||
if (leap == LEAP_Normal)
|
||||
leap = tz_leap;
|
||||
}
|
||||
|
||||
if (leap == LEAP_InsertSecond || leap == LEAP_DeleteSecond) {
|
||||
/* Check that leap second is allowed today */
|
||||
|
@ -773,12 +793,14 @@ update_leap_status(NTP_Leap leap, time_t now, int reset)
|
|||
}
|
||||
}
|
||||
|
||||
if (leap_sec != our_leap_sec && !REF_IsLeapSecondClose()) {
|
||||
if ((leap_sec != our_leap_sec || tai_offset != our_tai_offset)
|
||||
&& !REF_IsLeapSecondClose()) {
|
||||
our_leap_sec = leap_sec;
|
||||
our_tai_offset = tai_offset;
|
||||
|
||||
switch (leap_mode) {
|
||||
case REF_LeapModeSystem:
|
||||
LCL_SetSystemLeap(our_leap_sec, 0);
|
||||
LCL_SetSystemLeap(our_leap_sec, our_tai_offset);
|
||||
/* Fall through */
|
||||
case REF_LeapModeSlew:
|
||||
case REF_LeapModeStep:
|
||||
|
|
Loading…
Reference in a new issue