Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156748846
D36859.id111843.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D36859.id111843.diff
View Options
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -556,60 +556,43 @@
}
/*
- * Compute number of ticks in the specified amount of time.
+ * Compute number of ticks representing the specified amount of time.
+ * If the specified time is negative, a value of 1 is returned. This
+ * function returns a value from 1 up to and including INT_MAX.
*/
int
tvtohz(struct timeval *tv)
{
- unsigned long ticks;
- long sec, usec;
+ int retval;
/*
- * 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.
+ * The values passed here may come from user-space and these
+ * checks ensure "tv_usec" is within its allowed range:
*/
- sec = tv->tv_sec;
- usec = tv->tv_usec;
- if (usec < 0) {
- sec--;
- usec += 1000000;
- }
- if (sec < 0) {
-#ifdef DIAGNOSTIC
- if (usec > 0) {
- sec++;
- usec -= 1000000;
- }
- printf("tvotohz: negative time difference %ld sec %ld usec\n",
- sec, usec);
-#endif
- ticks = 1;
- } else if (sec <= LONG_MAX / 1000000)
- ticks = howmany(sec * 1000000 + (unsigned long)usec, tick) + 1;
- else if (sec <= LONG_MAX / hz)
- ticks = sec * hz
- + howmany((unsigned long)usec, tick) + 1;
- else
- ticks = LONG_MAX;
- if (ticks > INT_MAX)
- ticks = INT_MAX;
- return ((int)ticks);
+
+ /* check for tv_usec underflow */
+ if (__predict_false(tv->tv_usec < 0))
+ tv->tv_usec = 0;
+ /* check for tv_usec overflow */
+ else if (__predict_false(tv->tv_usec >= 1000000))
+ tv->tv_usec = 999999;
+
+ /* check for tv_sec underflow */
+ if (__predict_false(tv->tv_sec < 0))
+ return (1);
+ /* check for tv_sec overflow (including room for the tv_usec part) */
+ if (__predict_false(tv->tv_sec >= tick_seconds_max))
+ return (INT_MAX);
+
+ /* use "int" cast to avoid platform differences */
+ retval = (int)tv->tv_sec * hz + (int)(tv->tv_usec >> 6) * hz / (1000000 >> 6);
+
+ /* assert output range, just in case */
+ KASSERT(retval >= 0 && retval < INT_MAX,
+ ("tvtohz(): Assumptions are not met: %d %ld,%ld\n", retval, tv->tv_sec, tv->tv_usec));
+
+ /* add one additional tick */
+ return (retval + 1);
}
/*
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c
--- a/sys/kern/subr_param.c
+++ b/sys/kern/subr_param.c
@@ -84,6 +84,7 @@
int hz; /* system clock's frequency */
int tick; /* usec per tick (1000000 / hz) */
+int tick_seconds_max; /* max hz * seconds an integer can hold */
struct bintime tick_bt; /* bintime per tick (1s / hz) */
sbintime_t tick_sbt;
int maxusers; /* base tunable */
@@ -111,6 +112,10 @@
SYSCTL_INT(_kern, OID_AUTO, hz, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &hz, 0,
"Number of clock ticks per second");
+SYSCTL_INT(_kern, OID_AUTO, hz_max, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, HZ_MAXIMUM,
+ "Maximum hz value supported");
+SYSCTL_INT(_kern, OID_AUTO, hz_min, CTLFLAG_RD, SYSCTL_NULL_INT_PTR, HZ_MINIMUM,
+ "Minimum hz value supported");
SYSCTL_INT(_kern, OID_AUTO, nbuf, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &nbuf, 0,
"Number of buffers in the buffer cache");
SYSCTL_INT(_kern, OID_AUTO, nswbuf, CTLFLAG_RDTUN | CTLFLAG_NOFETCH, &nswbuf, 0,
@@ -173,9 +178,17 @@
TUNABLE_INT_FETCH("kern.hz", &hz);
if (hz == -1)
hz = vm_guest > VM_GUEST_NO ? HZ_VM : HZ;
+
+ /* range check the "hz" value */
+ if (__predict_false(hz < HZ_MINIMUM))
+ hz = HZ_MINIMUM;
+ else if (__predict_false(hz > HZ_MAXIMUM))
+ hz = HZ_MAXIMUM;
+
tick = 1000000 / hz;
tick_sbt = SBT_1S / hz;
tick_bt = sbttobt(tick_sbt);
+ tick_seconds_max = INT_MAX / hz;
/*
* Arrange for ticks to wrap 10 minutes after boot to help catch
diff --git a/sys/sys/time.h b/sys/sys/time.h
--- a/sys/sys/time.h
+++ b/sys/sys/time.h
@@ -505,6 +505,7 @@
extern volatile time_t time_uptime;
extern struct bintime tc_tick_bt;
extern sbintime_t tc_tick_sbt;
+extern int tick_seconds_max;
extern struct bintime tick_bt;
extern sbintime_t tick_sbt;
extern int tc_precexp;
@@ -583,6 +584,13 @@
void timevalsub(struct timeval *t1, const struct timeval *t2);
int tvtohz(struct timeval *tv);
+/*
+ * The following HZ limits allow the tvtohz() function
+ * to only use integer computations.
+ */
+#define HZ_MAXIMUM (INT_MAX / (1000000 >> 6)) /* 137kHz */
+#define HZ_MINIMUM 10 /* hz */
+
#define TC_DEFAULTPERC 5
#define BT2FREQ(bt) \
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, May 17, 2:28 AM (4 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33120341
Default Alt Text
D36859.id111843.diff (5 KB)
Attached To
Mode
D36859: time(3): Optimize tvtohz() function.
Attached
Detach File
Event Timeline
Log In to Comment