Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Dec 2006 00:45:57 -0600
From:      "Scot Hetzel" <swhetzel@gmail.com>
To:        "M. Warner Losh" <imp@bsdimp.com>
Cc:        youshi10@u.washington.edu, freebsd-current@freebsd.org
Subject:   Re: settimeofday function taking 24 - 30 minutes to complete
Message-ID:  <790a9fff0612222245n70994662y49aebed77c8eb45b@mail.gmail.com>
In-Reply-To: <20061220.185514.-345500127.imp@bsdimp.com>
References:  <45887A31.4050801@paradise.net.nz> <790a9fff0612191741r656fbbe0ic8660a9c59ba632b@mail.gmail.com> <45889598.3030408@u.washington.edu> <20061220.185514.-345500127.imp@bsdimp.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 12/20/06, M. Warner Losh <imp@bsdimp.com> wrote:
> It does run almost instantly if you use a time from 2000.  The date
> command also causes the lockup if you say 'date 1970010100140' as
> well.  Looks like there's a loop in the kernel to do division, but I
> can't quite find where it is.
>
> If you have a good test setup, maybe you can do a binary search in the
> settimeofday code to find why a large leap backwards causes problems.
>
Found the source of the problem by following the code in
kern_settimeofday (sys/kern/kern_time.c),  settime
(sys/kern/kern_time.c), and finally in resettodr
(sys/amd64/isa/clock.c).

/*
 * Write system time back to RTC
 */
void
resettodr()
{
:
	s = splclock();
	tm = time_second;
	splx(s);
:
	/* Calculate local time to put in RTC */
	tm -= utc_offset();

:
	/* We have now the days since 01-01-1970 in tm */
	writertc(RTC_WDAY, (tm + 4) % 7 + 1);		/* Write back Weekday */
	for (y = 1970, m = DAYSPERYEAR + LEAPYEAR(y);
	     tm >= m;
	     y++,      m = DAYSPERYEAR + LEAPYEAR(y))
	     tm -= m;
:
}

After adding some printf's to the resettodor, I was able to get some
interesting results:

hp010# ./t1
INFO: test running as root
INFO: Saved current time
settime: delta.tv_sec = - 1166842289
resettodr: tm = 100
resettodr: tm = -21500, utc_offset = 21600  <- value after subtracting
utc_offset()
resettodr: tm= 229, y = 426495804 <- the hang occurs in the
calculation for year.
INFO: settimeofday completed successfully
settime: delta.tv_sec = 1166840819
resettodr: tm = 1166842388
resettodr: tm = 1166820788
resettodr: tm = 355, y = 2006
INFO: Reset time to original value


By making the following change, the test program no longer hangs the system:

	/*
	 * Calculate local time to put in RTC
	 * Ignore UTC offset, if it would cause the time < Jan 1, 1970 00:00.
	 */
	if (tm >= utc_offset())
		tm -= utc_offset();
	else
		printf("resettodr: utc_offset > tm");

We probably need to change all the locations that use utc_offset(), to
have a similar "if (x >= utc_offset()) x -= utc_offset();".

Scot
-- 
DISCLAIMER:
No electrons were mamed while sending this message. Only slightly bruised.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?790a9fff0612222245n70994662y49aebed77c8eb45b>