Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 15 additions & 39 deletions timeout.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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];
Expand Down Expand Up @@ -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]) {
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand Down