]> granicus.if.org Git - libevent/commitdiff
Add an event_remove_timer() to remove timer on an event without deleting it
authorNick Mathewson <nickm@torproject.org>
Fri, 16 Nov 2012 21:15:03 +0000 (16:15 -0500)
committerNick Mathewson <nickm@torproject.org>
Fri, 16 Nov 2012 21:43:17 +0000 (16:43 -0500)
event-internal.h
event.c
include/event2/event.h
test/regress.c

index 36ece8434d4c7f8129a2853d5f5cbb3222e99eb7..614f5d800dc69a39d70d23006fc2621db71a765f 100644 (file)
@@ -383,6 +383,7 @@ int evsig_restore_handler_(struct event_base *base, int evsignal);
 int event_add_nolock_(struct event *ev,
     const struct timeval *tv, int tv_is_absolute);
 int event_del_nolock_(struct event *ev);
+int event_remove_timer_nolock_(struct event *ev);
 
 void event_active_nolock_(struct event *ev, int res, short count);
 int event_callback_activate_(struct event_base *, struct event_callback *);
diff --git a/event.c b/event.c
index fc3ceef54fd668bdfe4a6a2a155261462297bf5c..0fdd5d3317095b9e2b40727a4e0aae9557c5774d 100644 (file)
--- a/event.c
+++ b/event.c
@@ -2193,6 +2193,45 @@ evthread_notify_base(struct event_base *base)
        return base->th_notify_fn(base);
 }
 
+/* Implementation function to remove a timeout on a currently pending event.
+ */
+int
+event_remove_timer_nolock_(struct event *ev)
+{
+       struct event_base *base = ev->ev_base;
+
+       EVENT_BASE_ASSERT_LOCKED(base);
+       event_debug_assert_is_setup_(ev);
+
+       event_debug(("event_remove_timer_nolock: event: %p", ev));
+
+       /* If it's not pending on a timeout, we don't need to do anything. */
+       if (ev->ev_flags & EVLIST_TIMEOUT) {
+               event_queue_remove_timeout(base, ev);
+       }
+
+       return (0);
+}
+
+int
+event_remove_timer(struct event *ev)
+{
+       int res;
+
+       if (EVUTIL_FAILURE_CHECK(!ev->ev_base)) {
+               event_warnx("%s: event has no event_base set.", __func__);
+               return -1;
+       }
+
+       EVBASE_ACQUIRE_LOCK(ev->ev_base, th_base_lock);
+
+       res = event_remove_timer_nolock_(ev);
+
+       EVBASE_RELEASE_LOCK(ev->ev_base, th_base_lock);
+
+       return (res);
+}
+
 /* Implementation function to add an event.  Works just like event_add,
  * except: 1) it requires that we have the lock.  2) if tv_is_absolute is set,
  * we treat tv as an absolute time, not as an interval to add to the current
index 3eed8128066dba758ce11c54982b11ddb0e0ee98..4f177d9dcfd89db20a3876f9bbb617f6b9d84314 100644 (file)
@@ -1037,8 +1037,7 @@ int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_
   in calls to event_assign() until it is no longer pending.
 
   If the event in the ev argument already has a scheduled timeout, calling
-  event_add() replaces the old timeout with the new one, or clears the old
-  timeout if the timeout argument is NULL.
+  event_add() replaces the old timeout with the new one if tv is non-NULL.
 
   @param ev an event struct initialized via event_set()
   @param timeout the maximum amount of time to wait for the event, or NULL
@@ -1048,6 +1047,17 @@ int event_base_once(struct event_base *, evutil_socket_t, short, event_callback_
   */
 int event_add(struct event *ev, const struct timeval *timeout);
 
+/**
+   Remove a timer from a pending event without removing the event itself.
+
+   If the event has a scheduled timeout, this function unschedules it but
+   leaves the event otherwise pending.
+
+   @param ev an event struct initialized via event_assign() or event_new()
+   @return 0 on success, or -1 if  an error occurrect.
+*/
+int event_remove_timer(struct event *ev);
+
 /**
   Remove an event from the set of monitored events.
 
index 460ed581e2614d1c0558e35076b914ab91387487..e9e23ce5b7228a0763279995c5d18f4977c58353 100644 (file)
@@ -1410,6 +1410,71 @@ end:
        ;
 }
 
+
+static void incr_arg_cb(evutil_socket_t fd, short what, void *arg)
+{
+       int *intptr = arg;
+       (void) fd; (void) what;
+       ++*intptr;
+}
+static void remove_timers_cb(evutil_socket_t fd, short what, void *arg)
+{
+       struct event **ep = arg;
+       (void) fd; (void) what;
+       event_remove_timer(ep[0]);
+       event_remove_timer(ep[1]);
+}
+static void send_a_byte_cb(evutil_socket_t fd, short what, void *arg)
+{
+       evutil_socket_t *sockp = arg;
+       (void) fd; (void) what;
+       write(*sockp, "A", 1);
+}
+static void read_not_timeout_cb(evutil_socket_t fd, short what, void *arg)
+{
+       int *intp = arg;
+       (void) fd; (void) what;
+       *intp |= what;
+}
+
+static void
+test_event_remove_timeout(void *ptr)
+{
+       struct basic_test_data *data = ptr;
+       struct event_base *base = data->base;
+       struct event *ev[4];
+       int ev0_fired=0, ev1_fired=0;
+       struct timeval ms25 = { 0, 25*1000 },
+               ms75 = { 0, 75*1000 },
+               ms125 = { 0, 125*1000 };
+
+       event_base_assert_ok_(base);
+
+       ev[0] = event_new(base, data->pair[0], EV_READ,
+           read_not_timeout_cb, &ev0_fired);
+       ev[1] = evtimer_new(base, incr_arg_cb, &ev1_fired);
+       ev[2] = evtimer_new(base, remove_timers_cb, ev);
+       ev[3] = evtimer_new(base, send_a_byte_cb, &data->pair[1]);
+       tt_assert(base);
+       event_add(ev[2], &ms25); /* remove timers */
+       event_add(ev[0], &ms75); /* read */
+       event_add(ev[1], &ms75); /* timer */
+       event_add(ev[3], &ms125); /* timeout. */
+       event_base_assert_ok_(base);
+
+       event_base_dispatch(base);
+
+       tt_int_op(ev1_fired, ==, 0);
+       tt_int_op(ev0_fired, ==, EV_READ);
+
+       event_base_assert_ok_(base);
+end:
+       event_free(ev[0]);
+       event_free(ev[1]);
+       event_free(ev[2]);
+       event_free(ev[3]);
+}
+
 static void
 test_event_base_new(void *ptr)
 {
@@ -2559,6 +2624,7 @@ struct testcase_t main_testcases[] = {
        BASIC(bad_assign, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
        BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
        BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
+       BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
 
        /* These are still using the old API */
        LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),