mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Fix notifying the base in a different thread after removing active timer event
The base should be notified in case of timer removal if that was the minimal timer in the base. Reported-by: @moihn (who is also provided the reproducer on which this test is based on) Fixes: https://github.com/libevent/libevent/issues/1727
This commit is contained in:
parent
970a258bc6
commit
b219226982
10
event.c
10
event.c
@ -2926,13 +2926,9 @@ event_del_nolock_(struct event *ev, int blocking)
|
||||
}
|
||||
|
||||
if (ev->ev_flags & EVLIST_TIMEOUT) {
|
||||
/* NOTE: We never need to notify the main thread because of a
|
||||
* deleted timeout event: all that could happen if we don't is
|
||||
* that the dispatch loop might wake up too early. But the
|
||||
* point of notifying the main thread _is_ to wake up the
|
||||
* dispatch loop early anyway, so we wouldn't gain anything by
|
||||
* doing it.
|
||||
*/
|
||||
/* Notify the base if this was the minimal timeout */
|
||||
if (min_heap_top_(&base->timeheap) == ev)
|
||||
notify = 1;
|
||||
event_queue_remove_timeout(base, ev);
|
||||
}
|
||||
|
||||
|
@ -2063,6 +2063,58 @@ end:
|
||||
event_free(ev[4]);
|
||||
}
|
||||
|
||||
/* del_timeout_notify */
|
||||
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
||||
static THREAD_FN
|
||||
event_base_dispatch_threadcb(void *arg)
|
||||
{
|
||||
event_base_dispatch(arg);
|
||||
THREAD_RETURN();
|
||||
}
|
||||
|
||||
/* Regression test for the case when removing active event with EV_TIMEOUT does
|
||||
* not notifies the base properly like it should */
|
||||
static void
|
||||
test_del_timeout_notify(void *ptr)
|
||||
{
|
||||
struct basic_test_data *data = ptr;
|
||||
struct event_base *base = data->base;
|
||||
struct event *ev;
|
||||
struct timeval start_tv, now_tv;
|
||||
THREAD_T thread;
|
||||
|
||||
ev = event_new(base, -1, EV_PERSIST, null_cb, NULL);
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 5;
|
||||
tv.tv_usec = 0;
|
||||
event_add(ev, &tv);
|
||||
}
|
||||
|
||||
THREAD_START(thread, event_base_dispatch_threadcb, base);
|
||||
|
||||
/* FIXME: let's consider that 1 second is enough for the OS to spawn the
|
||||
* thread and enter event loop */
|
||||
{
|
||||
struct timeval delay = { 1, 0 };
|
||||
evutil_usleep_(&delay);
|
||||
}
|
||||
|
||||
evutil_gettimeofday(&start_tv, NULL);
|
||||
event_del(ev);
|
||||
THREAD_JOIN(thread);
|
||||
|
||||
evutil_gettimeofday(&now_tv, NULL);
|
||||
/* Let's consider that 1 second is enough to notify the base thread */
|
||||
tt_int_op(timeval_msec_diff(&start_tv, &now_tv), <, 1000);
|
||||
|
||||
event_base_assert_ok_(base);
|
||||
|
||||
end:
|
||||
event_free(ev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_event_base_new(void *ptr)
|
||||
{
|
||||
@ -3664,6 +3716,7 @@ struct testcase_t main_testcases[] = {
|
||||
#ifndef EVENT__DISABLE_THREAD_SUPPORT
|
||||
LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS|TT_RETRIABLE),
|
||||
LEGACY(del_notify, TT_ISOLATED|TT_NEED_THREADS),
|
||||
BASIC(del_timeout_notify, TT_NEED_THREADS|TT_FORK|TT_NEED_BASE),
|
||||
#endif
|
||||
|
||||
END_OF_TESTCASES
|
||||
|
Loading…
x
Reference in New Issue
Block a user