CVSROOT: /cvs Module name: src Changes by: chel...@cvs.openbsd.org 2020/07/16 17:06:43
Modified files: sys/kern : kern_tc.c Log message: adjtime(2): distribute skew along arbitrary period on runtime clock The adjtime(2) adjustment is applied at up to 5000ppm/sec from tc_windup(). At the start of each UTC second, ntp_update_second() is called from tc_windup() and up to 5000ppm worth of skew is deducted from the timehands' th_adjtimedelta member and moved to the th_adjustment member. The resulting th_adjustment value is then mixed into the th_scale member and thus the system UTC time is slowly nudged in a particular direction. This works pretty well. The only issues have to do with the use of the the edge of the UTC second as the start of the ntp_update_second() period: 1. If the UTC clock jumps forward we can get stuck in a loop calling ntp_update_second() from tc_windup(). We work around this with a magic number, LARGE_STEP. If the UTC clock jumps forward more than LARGE_STEP seconds we truncate the number of iterations to 2. Per the comment in tc_windup(), we do 2 iterations instead of 1 iteration to account for a leap second we may have missed. This is an anachronism: the OpenBSD kernel does not handle leap seconds anymore. Such jumps happen during settimeofday(2), during boot when we jump the clock from zero to the RTC time, and during resume when we jump the clock to the RTC time (again). They are unavoidable. 2. Changes to adjtime(2) are applied asynchronously. For example, if you try to cancel the ongoing adjustment... struct timeval zero = { 0, 0 }; adjtime(&zero, NULL); ... it can take up to one second for the adjustment to be cancelled. In the meantime, the skew continues. This delayed application is not intuitive or documented. 3. Adjustment is deducted from th_adjtimedelta across suspends of fewer than LARGE_STEP seconds, even though we do not skew the clock while we are suspended. This is unintuitive, incorrect, and undocumented. We can avoid all of these problems by applying the adjustment along an arbitrary period on the runtime clock instead of the UTC clock. 1. The runtime clock doesn't jump arbitrary amounts, so we never get stuck in a loop and we don't need a magic number to test for this possibility. With the removal of the magic number LARGE_STEP we can also remove the leap second handling from the tc_windup() code. 2. With a new timehands member, th_next_ntp_update, we can track when the next ntp_update_second() call should happen on the runtime clock. This value can be updated during the adjtime(2) system call, so changes to the skew happen *immediately* instead of up to one second after the adjtime(2) call. 3. The runtime clock does not jump across a suspend: no skew is deducted from th_adjtimedelta for any time we are offline and unable to adjust the clock. otto@ says the use of the runtime clock should not be a problem for ntpd(8) or the NTP algorithm in general.