pmtimer and nanouptime
YONETANI Tomokazu
qhwt+dragonfly-bugs at les.ath.cx
Tue Jul 20 04:45:21 PDT 2004
Hello.
On my PC, getnanotime() starts to return non-normalized value
(tv_nsec not between 0 and 999999999) after resuming from S3 state.
This breaks programs relying on the timespec value returned by
clock_gettime() to be normalized, and libc_r is one of them.
After inserting printf() in several places, I found the following things:
- getnanotime() returns non-normalized timespec value when
basetime.tv_nsec is out of range.
- basetime.tv_nsec becomes out of range when pmtimer_resume() calls
inittodr(0) which calls set_timeofday(), because nanouptime()
returns non-normalized value.
- nanouptime() returns non-normalized value when it's called from
set_timeofday() called from pmtimer_resume(), because of overflow
in multiplication. The following is modified version of nanouptime()
I'm using to print out each value used in multiplication.
nanouptime(struct timespec *tsp)
{
struct globaldata *gd = mycpu;
int64_t delta, nsec;
sysclock_t count, base;
do {
tsp->tv_sec = gd->gd_time_seconds;
count = cputimer_count();
base = gd->gd_cpuclock_base;
delta = count - base;
} while (tsp->tv_sec != gd->gd_time_seconds);
nsec = (cputimer_freq64_nsec * delta) >> 32;
if (nsec >= 1000000000) {
nsec -= 1000000000;
++tsp->tv_sec;
}
tsp->tv_nsec = nsec;
if (nsec < 0 || 1000000000 <= nsec) {
printf("nanouptime: nsec went negative;"
"delta: %lld, count: %u, base: %u, freq64_nsec: %lld"
"\n",
delta, count, base, cputimer_freq64_nsec);
}
}
And it printed out the following message on the console:
nanouptime: nsec went negative;delta: 8697958, count: 55705685, base: 47007727, freq64_nsec: 3599591090043
Here (cputimer_freq64_nsec * delta) doesn't fit within signed-64bit
and nsec becomes negative value, bypassing the following conditional.
I'm not sure what to change to fix this.
More information about the Bugs
mailing list