periodically save current time to time-of-day hardware

Peter Jeremy peterjeremy at acm.org
Sat Mar 27 21:46:47 UTC 2010


On 2010-Mar-27 01:38:36 +0100, Dag-Erling Smørgrav <des at des.no> wrote:
>Peter Jeremy <peterjeremy at acm.org> writes:
>> It's not especially important how regularly the RTC is updated, just
>> that it _is_ updated.  This suggests that an alternative approach
>> would be for adjtime() / ntp_adjtime() to directly call resettodr() if
>> it's more than P minutes since resettodr() was last called.
>
>It just occurred to me that resettodr() is very slow (it usually
>involves writing to NVRAM over an I2C bus), so it might not be a good
>idea to call it from adjtime().

Traditionally, the (PC) RTC is on the ISA bus (though it's possible it
might use I2C on other architectures or LPC on current PCs).  I thought
about speed but only in terms of simulated ISA accesses and didn't
think that adjtime() / ntp_adjtime() were especially time critical
(resettodr() should occur after they have updated the kernel TOD
parameters).  The alternative would be a kthread to update the RTC and
I didn't think that was worth it.

Note that resettodr() is currently called with Giant held so if it _is_
excesssively slow, it might be worthwhile reviewing the existing code
in kern_time.c::settime() and subr_clock.c::sysctl_machdep_adjkerntz().

>> As a general comment, whilst resettodr() needs to be serialised, there
>> is no need for it to block.  If thread B wants to call resettodr()
>> whilst thread A is doing so, thread B can just skip the call because
>> calling resettodr() twice in quick succession has no benefit.
>
>It does if thread B set the system clock before calling resettodr()
>(think ntpd -gq).

Yes - I hadn't considered resettodr() taking a non-trivial time to
execute.  This could allow the scenario: Thread A grabs the RTC update
lock and begin updating the RTC and, whilst it's doing so, thread B
updates the system clock and then calls resettodr() - which turns
into a no-op because the update lock is held.

>  Actually, it might be a good idea to call resettodr()
>any time the clock is stepped.

This should occur now via kern_time.c::settime().

Given that:
- resettodr() needs to be serialised;
- resettodr() may take a significant amount of time; and
- resettodr() should ideally be synchronised to the second boundary;
maybe creating a kthread to manage the RTC updating is reasonable.

A rough outline of my idea would be:

A new kthread which sleeps on channel "update_rtc".  When woken, it
checks to see if it's within (say) 50msec of a second boundary and so,
it does a trylock on the (new) RTC mutex.  If it grabs the mutex then
it performs the update.  If it was too far from the second boundary or
it fails to grab the mutex then it sleeps until the next second
boundary and tries again.

The existing resettodr() would then turn into a wakeup(update_rtc).

Or is this overkill?
-- 
Peter Jeremy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20100327/03f0eadf/attachment.pgp


More information about the freebsd-hackers mailing list