Messages in this thread | | | Date | Thu, 25 Feb 1999 23:21:07 -0700 (MST) | From | Colin Plumb <> | Subject | How to read xtime |
| |
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/
| |