Index: sys/sys/callout.h =================================================================== --- sys/sys/callout.h (revision 237576) +++ sys/sys/callout.h (working copy) @@ -51,9 +51,28 @@ #define CALLOUT_DIRECT 0x1000 /* allow exec from hw int context */ #define C_DIRECT_EXEC 0x0001 /* direct execution of callout */ -#define C_10US 0x0002 /* precision field */ -#define C_100US 0x0004 /* precision field */ -#define C_1MS 0x0008 /* precision field */ +#define C_P1S 0x0002 /* fields related to precision */ +#define C_P500MS 0x0006 +#define C_P250MS 0x000a +#define C_P125MS 0x000e +#define C_P64MS 0x0012 +#define C_P32MS 0x0016 +#define C_P16MS 0x001a +#define C_P8MS 0x001e +#define C_P4MS 0x0022 +#define C_P2MS 0x0026 +#define C_P1MS 0x002a +#define C_P500US 0x002e +#define C_P250US 0x0032 +#define C_P125US 0x0036 +#define C_P64US 0x003a +#define C_P32US 0x003e +#define C_P16US 0x0042 +#define C_P8US 0x0046 +#define C_P4US 0x004a +#define C_P2US 0x004e +#define PRECISION_BITS 7 +#define PRECISION_RANGE ((1 << PRECISION_BITS) - 1) struct callout_handle { struct callout *callout; Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c (revision 237576) +++ sys/kern/kern_timeout.c (working copy) @@ -497,8 +497,7 @@ struct bintime to_bintime, void (*func)(void *), void *arg, int cpu, int flags) { - struct timeval tv; - int bucket; + int bucket, r_shift, r_val; CC_LOCK_ASSERT(cc); if (bintime_cmp(&to_bintime, &cc->cc_lastscan, <)) { @@ -510,25 +509,38 @@ c->c_flags |= CALLOUT_DIRECT; c->c_flags &= ~CALLOUT_PROCESSED; c->c_func = func; - c->c_time = to_bintime; - tv.tv_sec = 0; - if (flags & C_10US) { - tv.tv_usec = 10; - timeval2bintime(&tv, &c->c_precision); - } - else if (flags & C_100US) { - tv.tv_usec = 100; - timeval2bintime(&tv, &c->c_precision); + c->c_time = to_bintime; + bintime_clear(&c->c_precision); + if (flags & 0x2) { + r_shift = ((flags >> 2) & PRECISION_RANGE); + r_val = (r_shift != 0) ? (uint64_t)1 << (64 - r_shift) : 0; + /* + * Round as far as precision specified is coarse (up to 8ms). + * In order to play safe, round to to half of the interval and + * set half precision. + */ + if (r_shift < 6) { + r_val = (r_shift != 0) ? r_val >> 2 : + ((uint64_t)1 << (64 - 1)) - 1; + /* + * Round only if c_time is not a multiple of the + * rounding factor. + */ + if ((c->c_time.frac & r_val) != r_val) { + c->c_time.frac |= r_val - 1; + c->c_time.frac += 1; + if (c->c_time.frac == 0) + c->c_time.sec += 1; + } + } + c->c_precision.frac = r_val; + CTR6(KTR_CALLOUT, "rounding %d.%u%u to %d.%u%u", + to_bintime.sec, (u_int) (to_bintime.frac >> 32), + (u_int) (to_bintime.frac & 0xffffffff), c->c_time.sec, + (u_int) (c->c_time.frac >> 32), + (u_int) (c->c_time.frac & 0xffffffff)); } - else if (flags & C_1MS) { - tv.tv_usec = 1000; - timeval2bintime(&tv, &c->c_precision); - } - else { - c->c_precision.sec = 0; - c->c_precision.frac = 0; - } - bucket = get_bucket(&c->c_time); + bucket = get_bucket(&c->c_time); TAILQ_INSERT_TAIL(&cc->cc_callwheel[bucket & callwheelmask], c, c_links.tqe); /* @@ -536,10 +548,10 @@ * that has been inserted. */ if (callout_new_inserted != NULL && - (bintime_cmp(&to_bintime, &cc->cc_firstevent, <) || + (bintime_cmp(&c->c_time, &cc->cc_firstevent, <) || (cc->cc_firstevent.sec == 0 && cc->cc_firstevent.frac == 0))) { - cc->cc_firstevent = to_bintime; - (*callout_new_inserted)(cpu, to_bintime); + cc->cc_firstevent = c->c_time; + (*callout_new_inserted)(cpu, c->c_time); } }