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);
|
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
|
||||||
gettime(base, &now);
|
gettime(base, &now);
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int was_active;
|
||||||
ev = TAILQ_FIRST(&ctl->events);
|
ev = TAILQ_FIRST(&ctl->events);
|
||||||
if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
|
if (!ev || ev->ev_timeout.tv_sec > now.tv_sec ||
|
||||||
(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))
|
(ev->ev_timeout.tv_usec&MICROSECONDS_MASK) > now.tv_usec))
|
||||||
break;
|
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);
|
event_active_nolock_(ev, EV_TIMEOUT, 1);
|
||||||
}
|
}
|
||||||
if (ev)
|
if (ev)
|
||||||
@ -3272,14 +3277,18 @@ timeout_process(struct event_base *base)
|
|||||||
gettime(base, &now);
|
gettime(base, &now);
|
||||||
|
|
||||||
while ((ev = min_heap_top_(&base->timeheap))) {
|
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, >))
|
if (evutil_timercmp(&ev->ev_timeout, &now, >))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* delete this event from the I/O queues */
|
if (!was_active)
|
||||||
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
event_del_nolock_(ev, EVENT_DEL_NOBLOCK);
|
||||||
|
else
|
||||||
|
event_queue_remove_timeout(base, ev);
|
||||||
|
|
||||||
event_debug(("timeout_process: event: %p, call %p",
|
event_debug(("timeout_process: event: %p, call %p (was active: %i)",
|
||||||
(void *)ev, (void *)ev->ev_callback));
|
(void *)ev, (void *)ev->ev_callback, was_active));
|
||||||
event_active_nolock_(ev, EV_TIMEOUT, 1);
|
event_active_nolock_(ev, EV_TIMEOUT, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2063,6 +2063,48 @@ end:
|
|||||||
event_free(ev[4]);
|
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 */
|
/* del_timeout_notify */
|
||||||
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
||||||
static THREAD_FN
|
static THREAD_FN
|
||||||
@ -3629,6 +3671,7 @@ struct testcase_t main_testcases[] = {
|
|||||||
BASIC(bad_reentrant, 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|TT_RETRIABLE),
|
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_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 */
|
/* These are still using the old API */
|
||||||
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
LEGACY(persistent_timeout, TT_FORK|TT_NEED_BASE),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user