Add an event_remove_timer() to remove timer on an event without deleting it

This commit is contained in:
Nick Mathewson 2012-11-16 16:15:03 -05:00
parent 5a9a014189
commit e3b2e0869e
4 changed files with 118 additions and 2 deletions

View 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 *);

39
event.c
View File

@ -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

View 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.

View 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),