diff --git a/timeout.c b/timeout.c index e78f57d..5ba99a6 100644 --- a/timeout.c +++ b/timeout.c @@ -305,24 +305,18 @@ TIMEOUT_PUBLIC void timeouts_del(struct timeouts *T, struct timeout *to) { } /* timeouts_del() */ -static inline reltime_t timeout_rem(struct timeouts *T, struct timeout *to) { - return to->expires - T->curtime; -} /* timeout_rem() */ - - -static inline int timeout_wheel(timeout_t timeout) { - /* must be called with timeout != 0, so fls input is nonzero */ - return (fls(MIN(timeout, TIMEOUT_MAX)) - 1) / WHEEL_BIT; +static inline int timeout_wheel(timeout_t curtime, timeout_t expires) { + /* must be called with expires > curtime, so fls input is nonzero */ + return (fls(MIN(curtime ^ expires, TIMEOUT_MAX)) - 1) / WHEEL_BIT; } /* timeout_wheel() */ static inline int timeout_slot(int wheel, timeout_t expires) { - return WHEEL_MASK & ((expires >> (wheel * WHEEL_BIT)) - !!wheel); + return WHEEL_MASK & ((expires >> (wheel * WHEEL_BIT))); } /* timeout_slot() */ static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t expires) { - timeout_t rem; int wheel, slot; timeouts_del(T, to); @@ -332,14 +326,7 @@ static void timeouts_sched(struct timeouts *T, struct timeout *to, timeout_t exp TO_SET_TIMEOUTS(to, T); if (expires > T->curtime) { - rem = timeout_rem(T, to); - - /* rem is nonzero since: - * rem == timeout_rem(T,to), - * == to->expires - T->curtime - * and above we have expires > T->curtime. - */ - wheel = timeout_wheel(rem); + wheel = timeout_wheel(T->curtime, expires); slot = timeout_slot(wheel, to->expires); to->pending = &T->wheel[wheel][slot]; @@ -402,34 +389,26 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) { /* * Calculate the slots expiring in this wheel * - * If the elapsed time is greater than the maximum period of + * Assume that current slot is empty, it's timer either expired or moved to the lower wheel. + * If the elapsed time is greater or equal to the maximum period of * the wheel, mark every position as expiring. * * Otherwise, to determine the expired slots fill in all the * bits between the last slot processed and the current - * slot, inclusive of the last slot. We'll bitwise-AND this + * slot(exclusive, we don't need to check it again), inclusive of the last slot. We'll bitwise-AND this * with our pending set below. - * - * If a wheel rolls over, force a tick of the next higher - * wheel. */ - if ((elapsed >> (wheel * WHEEL_BIT)) > WHEEL_MAX) { + if ((elapsed >> (wheel * WHEEL_BIT)) >= WHEEL_MAX) { pending = (wheel_t)~WHEEL_C(0); } else { - wheel_t _elapsed = WHEEL_MASK & (elapsed >> (wheel * WHEEL_BIT)); + wheel_t _elapsed; int oslot, nslot; - /* - * TODO: It's likely that at least one of the - * following three bit fill operations is redundant - * or can be replaced with a simpler operation. - */ oslot = WHEEL_MASK & (T->curtime >> (wheel * WHEEL_BIT)); - pending = rotl(((UINT64_C(1) << _elapsed) - 1), oslot); - nslot = WHEEL_MASK & (curtime >> (wheel * WHEEL_BIT)); - pending |= rotr(rotl(((WHEEL_C(1) << _elapsed) - 1), nslot), _elapsed); - pending |= WHEEL_C(1) << nslot; + _elapsed = WHEEL_MASK & (WHEEL_LEN + nslot - oslot); + + pending = rotl(((WHEEL_C(1) << _elapsed) - 1), oslot + 1); } while (pending & T->pending[wheel]) { @@ -441,9 +420,6 @@ TIMEOUT_PUBLIC void timeouts_update(struct timeouts *T, abstime_t curtime) { if (!(0x1 & pending)) break; /* break if we didn't wrap around end of wheel */ - - /* if we're continuing, the next wheel must tick at least once */ - elapsed = MAX(elapsed, (WHEEL_LEN << (wheel * WHEEL_BIT))); } T->curtime = curtime; @@ -512,8 +488,8 @@ static timeout_t timeouts_int(struct timeouts *T) { /* ctz input cannot be zero: T->pending[wheel] is * nonzero, so rotr() is nonzero. */ - _timeout = (ctz(rotr(T->pending[wheel], slot)) + !!wheel) << (wheel * WHEEL_BIT); - /* +1 to higher order wheels as those timeouts are one rotation in the future (otherwise they'd be on a lower wheel or expired) */ + _timeout = (ctz(rotr(T->pending[wheel], slot)) + !!(T->pending[wheel] & (TIMEOUT_C(1) << slot))) << (wheel * WHEEL_BIT); + /* +1 when a timeout greater than TIMEOUT_MAX and wrap in to current slot of the highest wheel */ _timeout -= relmask & T->curtime; /* reduce by how much lower wheels have progressed */