Commit d00a3762 authored by Nick Mathewson's avatar Nick Mathewson

Correct and simplify timeouts_readd()

William Ahern tells me that the intent here is that timeout_readd()
should always reschedule the timeout at the first time in the future
that is an even multiple of to->interval, as if we had called:

         do {
                 to->expires += to->interval;
         } while (to->expires <= T->curtime);

But of course, that's not efficient.  The implementation strategy
used in this patch simplifies the calculation down to a single %
operation, plus a few additions and subtractions.

To verify the correctness of the formula used here, note first that
        0 <= r < to->interval, and so
        0 < to->interval - r <= to->interval.  Since
        expires' = curtime + (interval - r),
        curtime < expires' <= curtime + interval,
and so the new expiration time is no more than one interval after
curtime.

Note second that since
        r = (curtime - expires) % interval,
        expires' = curtime + (interval - r), we have
        (expires' - expires) % interval =
            (curtime + (interval - r) - expires) % interval =
            (curtime - r - expires) % interval =
            (curtime - (curtime-expires) % interval - expires) % interval =
            (curtime - curtime + expires - expires) % interval =
            0.
And so the new expiration time is an even multiple of interval from
the original expiration time.

Since we have both properties we wanted, this formula should be right.
parent 51e9aae0
...@@ -358,18 +358,13 @@ static void timeouts_readd(struct timeouts *T, struct timeout *to) { ...@@ -358,18 +358,13 @@ static void timeouts_readd(struct timeouts *T, struct timeout *to) {
to->expires += to->interval; to->expires += to->interval;
if (to->expires <= T->curtime) { if (to->expires <= T->curtime) {
if (to->expires < T->curtime) { /* If we've missed the next firing of this timeout, reschedule
timeout_t n = T->curtime - to->expires; * it to occur at the next multiple of its interval after
timeout_t q = n / to->interval; * the last time that it fired.
timeout_t r = n % to->interval; */
timeout_t n = T->curtime - to->expires;
if (r) timeout_t r = n % to->interval;
to->expires += (to->interval * q) + (to->interval - r); to->expires = T->curtime + (to->interval - r);
else
to->expires += (to->interval * q);
} else {
to->expires += to->interval;
}
} }
timeouts_sched(T, to, to->expires); timeouts_sched(T, to, to->expires);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment