How to read xtime

Colin Plumb (colin@nyx.net)
Thu, 25 Feb 1999 23:21:07 -0700 (MST)


Locks are *slow*. Wrapping one around xtime seems unnecessary.

Here's a simple hack. It assumes that interrupts or whatever never
cause more than 1/2 second of delay in the time it takes a single
processor to execute get_xtime(). Solutions that address that are
a bit more complex, but still not bad.

unsigned xtime_sec1; /* When incrementing xtime, write this forst */
unsigned xtime_usec; /* Then this */
unsigned xtime_sec2; /* Then this */

struct timeval
inc_xtime(unsigned usec_delta)
{
unsigned sec = xtime_sec1;
unsigned usec = xtime_usec + usec_delta;

if (usec < 1000000) {
xtime_usec = usec;
} else {
xtime_sec1 = ++sec;
xtime_usec = usec -= 1000000;
xtime_sec2 = sec;
}
return (struct timeval){sec, usec};
}

struct timeval
get_xtime(void)
{
unsigned sec = xtime_sec2;
unsigned usec = xtime_usec;

if (usec < 5000000)
sec = xtime_sec1;
return (struct timeval){sec, usec};
}

With the appropriate mb() calls inserted to make sure the reads and writes
get to the bus in program order, this works nicely. Basically, the time
is written when the usec field is updated.

In the first half of the second, the danger is that you'll get an old
seconds field, and read 1.00 seconds when it's supposed to be 2.00
because the update from 1.99 hasn't finished. Thus, we use xtime_sec1,
which is written before xtime_usec and read after it, so there is no
chance of a problem.

In the second half of a second, the danger is that you'll get a new seconds
field, and read 2.99 seconds when it's really 1.99 being updated to 2.0.
In this case, we use xtime_sec2, which is written after xtime_usec and
read before it, so again there is no chance of a problem.

As long as interrupt handling doesn't make get_xtime() take too long,
there should be no problem. Will interrupt handlers ever take longer
than that often enough that slightly wonky results will matter?

Useful details when developing other techniques:
If you increment from MSW to LSW and read from LSW to MSW, you can
only ever read too high; you will never read too low. The other
way around, you will only ever read too high.

Using this, it's possible to develop a non-looping read algorithm
that always returns a time that is within the span of times through
which xtime has passed. If the two reads of xtime_sec2 and xtime_sec1
differ, then just return a time known to be somewhere in the interval,
e.g. xtime_sec1 and 0 usec.

Locks are slow and to be avoided.

-- 
	-Colin

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/