mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Avoid loosing previously active events in case of EV_TIMEOUT
Previously all the existing events was lost if the timeout had been triggered on that event. Fixes: #1530
This commit is contained in:
parent
528fbed184
commit
342a0faa50
19
event.c
19
event.c
@ -1505,12 +1505,17 @@ common_timeout_callback(evutil_socket_t fd, short what, void *arg)
|
||||
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
|
||||
gettime(base, &now);
|
||||
while (1) {
|
||||
int was_active;
|
||||
ev = TAILQ_FIRST(&ctl->events);
|
||||
if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
|
||||
(ev->ev_timeout.tv_sec == now.tv_sec &&
|
||||
(ev->ev_timeout.tv_usec&MICROSECONDS_MASK) > now.tv_usec))
|
||||
break;
|
||||
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
||||
was_active = ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER);
|
||||
if (!was_active)
|
||||
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
||||
else
|
||||
event_queue_remove_timeout(base, ev);
|
||||
event_active_nolock_(ev, EV_TIMEOUT, 1);
|
||||
}
|
||||
if (ev)
|
||||
@ -3272,14 +3277,18 @@ timeout_process(struct event_base *base)
|
||||
gettime(base, &now);
|
||||
|
||||
while ((ev = min_heap_top_(&base->timeheap))) {
|
||||
int was_active = ev->ev_flags & (EVLIST_ACTIVE|EVLIST_ACTIVE_LATER);
|
||||
|
||||
if (evutil_timercmp(&ev->ev_timeout, &now, >))
|
||||
break;
|
||||
|
||||
/* delete this event from the I/O queues */
|
||||
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
||||
if (!was_active)
|
||||
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
||||
else
|
||||
event_queue_remove_timeout(base, ev);
|
||||
|
||||
event_debug(("timeout_process: event: %p, call %p",
|
||||
(void *)ev, (void *)ev->ev_callback));
|
||||
event_debug(("timeout_process: event: %p, call %p (was active: %i)",
|
||||
(void *)ev, (void *)ev->ev_callback, was_active));
|
||||
event_active_nolock_(ev, EV_TIMEOUT, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2063,6 +2063,48 @@ end:
|
||||
event_free(ev[4]);
|
||||
}
|
||||
|
||||
static void
|
||||
test_event_timeout_lost_cb(evutil_socket_t fd, short events, void *arg)
|
||||
{
|
||||
short *res_events = arg;
|
||||
*res_events = events;
|
||||
}
|
||||
static void
|
||||
test_event_timeout_lost(void *ptr)
|
||||
{
|
||||
struct basic_test_data *data = ptr;
|
||||
struct event_base *base = data->base;
|
||||
struct event *ev;
|
||||
short res_events = 0;
|
||||
|
||||
event_base_assert_ok_(base);
|
||||
|
||||
ev = event_new(base, data->pair[0], EV_TIMEOUT|EV_READ, test_event_timeout_lost_cb, &res_events);
|
||||
tt_assert(ev);
|
||||
|
||||
{
|
||||
struct timeval timeout = { 0, 100 };
|
||||
event_add(ev, &timeout);
|
||||
}
|
||||
|
||||
event_active(ev, EV_READ, 1);
|
||||
|
||||
/* Ensure that timeout had been elapsed */
|
||||
{
|
||||
struct timeval delay = { 1, 0 };
|
||||
evutil_usleep_(&delay);
|
||||
}
|
||||
|
||||
event_base_assert_ok_(base);
|
||||
event_base_loop(base, EVLOOP_ONCE|EVLOOP_NONBLOCK);
|
||||
event_base_assert_ok_(base);
|
||||
|
||||
tt_int_op(res_events, ==, EV_READ|EV_TIMEOUT);
|
||||
|
||||
end:
|
||||
event_free(ev);
|
||||
}
|
||||
|
||||
/* del_timeout_notify */
|
||||
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
||||
static THREAD_FN
|
||||
@ -3629,6 +3671,7 @@ struct testcase_t main_testcases[] = {
|
||||
BASIC(bad_reentrant, TT_FORK|TT_NEED_BASE|TT_NO_LOGS),
|
||||
BASIC(active_later, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR|TT_RETRIABLE),
|
||||
BASIC(event_remove_timeout, TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR),
|
||||
BASIC(event_timeout_lost, TT_FORK|TT_NEED_BASE),
|
||||
|
||||
/* These are still using the old API */
|
||||
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
||||
|
Loading…
x
Reference in New Issue
Block a user