Index: sys/sys/callout.h =================================================================== --- sys/sys/callout.h (revision 243099) +++ sys/sys/callout.h (working copy) @@ -96,7 +96,7 @@ int _callout_reset_on(struct callout *, struct bin (0)) #define callout_reset_flags_on(c, to_ticks, fn, arg, cpu, flags) \ _callout_reset_on((c), (NULL), (to_ticks), (fn), (arg), (cpu), \ - (flags)) + (flags)) #define callout_reset_bt_on(c, bt, fn, arg, cpu, flags) \ _callout_reset_on((c), (bt), (0), (fn), (arg), (cpu), (flags)) #define callout_reset(c, on_tick, fn, arg) \ Index: sys/sys/time.h =================================================================== --- sys/sys/time.h (revision 243099) +++ sys/sys/time.h (working copy) @@ -352,7 +352,7 @@ int tvtohz(struct timeval *tv); ((bt)->frac >> 1)) #define TIMESEL(x, bt) \ - ((x) < tc_timethreshold ? (binuptime : getbinuptime(&(bt))) + ((x) < tc_timethreshold ? binuptime(&(bt)) : getbinuptime(&(bt))) #else /* !_KERNEL */ Index: sys/kern/kern_time.c =================================================================== --- sys/kern/kern_time.c (revision 243099) +++ sys/kern/kern_time.c (working copy) @@ -483,35 +483,48 @@ int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) { struct timespec ts; - struct bintime bt, bt2, tmp; - int error; + struct bintime bt, bt2, bt_prec, tmp; + int carry, flags, k, error; if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) return (0); - binuptime(&bt); + TIMESEL(rqt->tv_nsec, bt); timespec2bintime(rqt, &tmp); - bintime_add(&bt,&tmp); - for (;;) { - error = tsleep_bt(&nanowait, PWAIT | PCATCH, "nanslp", &bt, 0); - binuptime(&bt2); - if (error != EWOULDBLOCK) { - if (error == ERESTART) - error = EINTR; - if (rmt != NULL) { - tmp = bt; - bintime_sub(&tmp, &bt2); - bintime2timespec(&tmp, &ts); - if (ts.tv_sec < 0) - timespecclear(&ts); - *rmt = ts; - } - return (error); + bintime_add(&bt, &tmp); + k = 4; + bt_prec = tmp; + bt_prec.frac >>= k; + carry = bt_prec.sec & ((1 << k) - 1); + bt_prec.sec >>= k; + bt_prec.frac |= (carry) ? ~(((uint64_t)1 << (64 - carry)) - 1) : 0; + if (rqt->tv_nsec > tc_timethreshold) { + bintime_add(&bt, &tick_bt); + if (bintime_cmp(&bt_prec, &tick_bt, <)) + bt_prec = tick_bt; + } + flags = C_DIRECT_EXEC; + k = C_BT2PABS(bt_prec.frac); + flags |= C_SETPABS(k); + error = tsleep_bt(&nanowait, PWAIT | PCATCH, "nanslp", &bt, flags); + TIMESEL(rqt->tv_nsec, bt2); + if (error != EWOULDBLOCK) { + if (error == ERESTART) + error = EINTR; + if (rmt != NULL) { + tmp = bt; + bintime_sub(&tmp, &bt2); + bintime2timespec(&tmp, &ts); + if (ts.tv_sec < 0) + timespecclear(&ts); + *rmt = ts; } if (bintime_cmp(&bt2, &bt, >=)) return (0); + return (error); } + return (0); } #ifndef _SYS_SYSPROTO_H_