]> granicus.if.org Git - libevent/commitdiff
Fix a bug in resetting timeouts on persistent events when IO triggers.
authorNick Mathewson <nickm@torproject.org>
Tue, 23 Feb 2010 19:24:10 +0000 (14:24 -0500)
committerNick Mathewson <nickm@torproject.org>
Tue, 23 Feb 2010 20:20:33 +0000 (15:20 -0500)
When we fixed persistent timeouts to make them reset themselves
based on the previous scheduled time rather than the current
time... we made them do so regardless of whether the event was
triggering because of a timeout or not!

This was of course bogus.  When a _timeout_ triggers, we should
schedule the event for N seconds based on the last
_schedule_ time... but when IO triggers, we should reset the
timeout for N seconds after now.

event.c

diff --git a/event.c b/event.c
index 07a4336297d92d25d0903000f935f85301d1f453..e66fb30c5797025ec8e571201f4a337c10797990 100644 (file)
--- a/event.c
+++ b/event.c
@@ -1083,24 +1083,35 @@ event_persist_closure(struct event_base *base, struct event *ev)
 {
        /* reschedule the persistent event if we have a timeout. */
        if (ev->ev_io_timeout.tv_sec || ev->ev_io_timeout.tv_usec) {
-               /* We want it to run at an interval of ev_io_timeout after the
-                * last time it was _scheduled_ for, not ev_io_timeout after
-                * _now_. */
+               /* If there was a timeout, we want it to run at an interval of
+                * ev_io_timeout after the last time it was _scheduled_ for,
+                * not ev_io_timeout after _now_.  If it fired for another
+                * reason, though, the timeout ought to start ticking _now_. */
                struct timeval run_at;
                EVUTIL_ASSERT(is_same_common_timeout(&ev->ev_timeout,
                        &ev->ev_io_timeout));
                if (is_common_timeout(&ev->ev_timeout, base)) {
                        ev_uint32_t usec_mask;
-                       struct timeval delay, last_at;
-                       last_at = ev->ev_timeout;
+                       struct timeval delay, relative_to;
                        delay = ev->ev_io_timeout;
                        usec_mask = delay.tv_usec & ~MICROSECONDS_MASK;
-                       last_at.tv_usec &= MICROSECONDS_MASK;
                        delay.tv_usec &= MICROSECONDS_MASK;
-                       evutil_timeradd(&last_at, &delay, &run_at);
+                       if (ev->ev_res & EV_TIMEOUT) {
+                               relative_to = ev->ev_timeout;
+                               relative_to.tv_usec &= MICROSECONDS_MASK;
+                       } else {
+                               gettime(base, &relative_to);
+                       }
+                       evutil_timeradd(&relative_to, &delay, &run_at);
                        run_at.tv_usec |= usec_mask;
                } else {
-                       evutil_timeradd(&ev->ev_io_timeout, &ev->ev_timeout,
+                       struct timeval relative_to;
+                       if (ev->ev_res & EV_TIMEOUT) {
+                               relative_to = ev->ev_timeout;
+                       } else {
+                               gettime(base, &relative_to);
+                       }
+                       evutil_timeradd(&ev->ev_io_timeout, &relative_to,
                            &run_at);
                }
                event_add_internal(ev, &run_at, 1);