[ntp:questions] LOCL clock reachability not 377?
William Unruh
unruh at invalid.ca
Thu Jul 31 22:34:57 UTC 2014
On 2014-07-31, William Unruh <unruh at invalid.ca> wrote:
> On 2014-07-31, Rob <nomail at example.com> wrote:
>> William Unruh <unruh at invalid.ca> wrote:
>>>> Why? The time is copied to the CMOS clock regularly, and one could
>>>> expect that during the short reboot the CMOS would not drift away so
>>>> much that the time could not be synced to the PPS unambiguously.
>>>
>>> Sure it could. And how does the system know what a "short reboot" is.
>>> ntpd can hardly be expected to root throught the filesysytem trying to
>>> figure out how long it has been since last boot, or how far off the rtc
>>> is. ntpd distrusts the rtc at the best of times.
>>
>> Well, ntpd reads the stored estimated frequency error from disk too.
>> The fact that it does all that is within its capacity to destroy this
>> value does not matter.
>>
>>>> No, the problem is that the CMOS can only be set to an accuracy of one
>>>> second.
>>>
>>> Well, actually no. It can be set to an accuracy of about 1usec. And read
>>> to that accuracy. It only reports the time the second it is true. But It
>>> emits an interrupt on the turnover of the second. Of course for some
>>> Linux kernels, the handling of that interrupt is seriously broken, but
>>> even then it can be read by polling to a few usec.
>>> Setting is a rococo procedure. You have to write to the rtc something
>>> like .5 sec before you want that second to fall. But that can set it to
>>> usec accuracy.
>>
>> You are mistaken. The running clock in Linux can be set and read that
>> accurately, but not the CMOS clock.
>
> I think you need to read up on the cmos clock. As I said, it reports
> only the seconds, but is settable and "readable" to microseconds.
> The seconds rollover is exactly on the second so polling could do it,
> but it also issues and interrupt. And it is also settable to the order
> of microseconds.
> Look at the code in hwclock as an example. Or the code in chrony.
>
Just so you do not have to take my word, here the comments in hwclock.c
/*
* The Hardware Clock can only be set to any integer time plus
* one
* half second. The integer time is required because there is
* no
* interface to set or get a fractional second. The additional
* half
* second is because the Hardware Clock updates to the following
* second precisely 500 ms (not 1 second!) after you release the
* divider reset (after setting the new time) - see description
* of
* DV2, DV1, DV0 in Register A in the MC146818A data sheet (and
* note
* that although that document doesn't say so, real-world code
* seems
* to expect that the SET bit in Register B functions the same
* way).
* That means that, e.g., when you set the clock to 1:02:03, it
* effectively really sets it to 1:02:03.5, because it will
* update to
* 1:02:04 only half a second later. Our caller passes the
* desired
* integer Hardware Clock time in sethwtime, and the
* corresponding
* system time (which may have a fractional part, and which may
* or may
* not be the same!) in refsystime. In an ideal situation, we
* would
* then apply sethwtime to the Hardware Clock at
* refsystime+500ms, so
* that when the Hardware Clock ticks forward to sethwtime+1s
* half a
* second later at refsystime+1000ms, everything is in sync. So
* we
* spin, waiting for gettimeofday() to return a time at or after
* that
* time (refsystime+500ms) up to a tolerance value, initially
* 1ms. If
* we miss that time due to being preempted for some other
* process,
* then we increase the margin a little bit (initially 1ms,
* doubling
* each time), add 1 second (or more, if needed to get a time
* that is
* in the future) to both the time for which we are waiting and
* the
* time that we will apply to the Hardware Clock, and start
* waiting
* again.
*
* For example, the caller requests that we set the Hardware
* Clock to
* 1:02:03, with reference time (current system time) =
* 6:07:08.250.
* We want the Hardware Clock to update to 1:02:04 at
* 6:07:09.250 on
* the system clock, and the first such update will occur 0.500
* seconds after we write to the Hardware Clock, so we spin
* until the
* system clock reads 6:07:08.750. If we get there, great, but
* let's
* imagine the system is so heavily loaded that our process is
* preempted and by the time we get to run again, the system
* clock
* reads 6:07:11.990. We now want to wait until the next
* xx:xx:xx.750
* time, which is 6:07:12.750 (4.5 seconds after the reference
* time),
* at which point we will set the Hardware Clock to 1:02:07 (4
* seconds
* after the originally requested time). If we do that
* successfully,
* then at 6:07:13.250 (5 seconds after the reference time), the
* Hardware Clock will update to 1:02:08 (5 seconds after the
* originally requested time), and all is well thereafter.
*/
And here are the comments for reading the time.
/*
* Wait until the falling edge of the Hardware Clock's update flag so
* that
* any time that is read from the clock immediately after we return will
* be
* exact.
*
* The clock only has 1 second precision, so it gives the exact time
* only
* once per second, right on the falling edge of the update flag.
*
* We wait (up to one second) either blocked waiting for an rtc device
* or in
* a CPU spin loop. The former is probably not very accurate.
*
* Return 0 if it worked, nonzero if it didn't.
More information about the questions
mailing list