[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