From 97f72ceecc264ed6a8f66ec5f7d64f289f8b306f Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Fri, 20 Jun 2014 16:32:50 +0200 Subject: [PATCH] linreg: Handle leap second gracefully. When leap second is inserted/deleted to the reference time, adjust the reference point as if the clock was stepped in the opposite direction to keep the slope and error statistics valid and correct the offset gracefully. Signed-off-by: Miroslav Lichvar --- linreg.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/linreg.c b/linreg.c index 4513dd1..b94c44e 100644 --- a/linreg.c +++ b/linreg.c @@ -76,6 +76,8 @@ struct linreg_servo { double update_interval; /* Current ratio between remote and local frequency */ double frequency_ratio; + /* Upcoming leap second */ + int leap; }; static void linreg_destroy(struct servo *servo) @@ -305,6 +307,20 @@ static double linreg_rate_ratio(struct servo *servo) return s->frequency_ratio; } +static void linreg_leap(struct servo *servo, int leap) +{ + struct linreg_servo *s = container_of(servo, struct linreg_servo, servo); + + /* + * Move reference when leap second is applied to the reference + * time as if the clock was stepped in the opposite direction + */ + if (s->leap && !leap) + move_reference(s, 0, s->leap * 1000000000); + + s->leap = leap; +} + struct servo *linreg_servo_create(int fadj) { struct linreg_servo *s; @@ -318,6 +334,7 @@ struct servo *linreg_servo_create(int fadj) s->servo.sync_interval = linreg_sync_interval; s->servo.reset = linreg_reset; s->servo.rate_ratio = linreg_rate_ratio; + s->servo.leap = linreg_leap; s->clock_freq = -fadj; s->frequency_ratio = 1.0;