My newyear's resolution is...
Matthew Dillon
dillon at apollo.backplane.com
Tue Jan 6 21:01:45 PST 2004
Ok, I've spent some time looking at your patch set. I modified your
tvtohz() changes to guarentee a minimum return value of 1 without
the unconditional + 1 that was messing up the original calculation, which
you fixed, as you suggested. That patch is enclosed. I cleaned up
the rest of the function a bit too (not tested as yet).
This simplifies your kern_time.c patch and maintains the original tvtohz()
API, but there is still an issue with the last bit of your kern_time.c
patch:
+ if (tv.tv_sec == 0 && tv.tv_usec < tick)
+ return (0);
The problem is that this may break the guarentee that it sleeps at least
as long as requested. The original tvtohz() calculation only guarentees
that the ticks calculation will be at least enough, not that it will be
more then enough, but if the calculation occurs just before a clock
interrupt then the '1 tick minimum' might only be a few microseconds.
I think the reason this did not show up in your tests is because the
tsleep() will synchronize with a clock tick anyway, so all your loops
except the first one will be hitting nanosleep() just after a clock
interrupt instead of just before.
So if we calculate less then a tick left to go in the nanosleep loop,
we still either have to tsleep for a tick, or hard-loop or soft switch
until the timeout completes. Soft switching is an option... it involves
calling uio_yield() in a loop instead of tsleep()ing until the remainder
of the timeout has been dealt with. We could make nanosleep() extremely
accurate in this fashion (at least as long as there are no other
cpu bound processes running) but it would waste a lot more cpu even
with a uio_yield()
-Matt
Matthew Dillon
<dillon at xxxxxxxxxxxxx>
Index: kern_clock.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_clock.c,v
retrieving revision 1.12
diff -u -r1.12 kern_clock.c
--- kern_clock.c 17 Oct 2003 07:30:42 -0000 1.12
+++ kern_clock.c 7 Jan 2004 04:16:24 -0000
@@ -268,35 +268,23 @@
}
/*
- * Compute number of ticks in the specified amount of time.
+ * Compute number of ticks for the specified amount of time. If the
+ * representation overflows, return INT_MAX. The minimum return value is 1
+ * tick.
+ *
+ * Note that limit checks must take into account microseconds, which is
+ * done simply by using the smaller signed long maximum instead of
+ * the unsigned long maximum.
+ *
+ * If ints have 32 bits, then the maximum value for any timeout in
+ * 10ms ticks is 248 days.
*/
int
-tvtohz(tv)
- struct timeval *tv;
+tvtohz(struct timeval *tv)
{
- unsigned long ticks;
+ int ticks;
long sec, usec;
- /*
- * If the number of usecs in the whole seconds part of the time
- * difference fits in a long, then the total number of usecs will
- * fit in an unsigned long. Compute the total and convert it to
- * ticks, rounding up and adding 1 to allow for the current tick
- * to expire. Rounding also depends on unsigned long arithmetic
- * to avoid overflow.
- *
- * Otherwise, if the number of ticks in the whole seconds part of
- * the time difference fits in a long, then convert the parts to
- * ticks separately and add, using similar rounding methods and
- * overflow avoidance. This method would work in the previous
- * case but it is slightly slower and assumes that hz is integral.
- *
- * Otherwise, round the time difference down to the maximum
- * representable value.
- *
- * If ints have 32 bits, then the maximum value for any timeout in
- * 10ms ticks is 248 days.
- */
sec = tv->tv_sec;
usec = tv->tv_usec;
if (usec < 0) {
@@ -313,17 +301,14 @@
sec, usec);
#endif
ticks = 1;
- } else if (sec <= LONG_MAX / 1000000)
- ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
- / tick + 1;
- else if (sec <= LONG_MAX / hz)
- ticks = sec * hz
- + ((unsigned long)usec + (tick - 1)) / tick + 1;
- else
- ticks = LONG_MAX;
- if (ticks > INT_MAX)
+ } else if (sec <= INT_MAX / hz) {
+ ticks = (int)(sec * hz + ((u_long)usec + (tick - 1)) / tick);
+ } else {
ticks = INT_MAX;
- return ((int)ticks);
+ }
+ if (ticks == 0)
+ ticks = 1;
+ return (ticks);
}
/*
More information about the Bugs
mailing list