From: José Luis Millán Date: Mon, 13 Apr 2015 06:54:52 +0000 (+0200) Subject: Return from event_del() after the last event callback termination X-Git-Tag: release-2.1.9-beta^2~182 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=876c7ac7ff86a4cf9d772d1bf129b59d0a08d80c;p=libevent Return from event_del() after the last event callback termination Delete the event from the queue before blocking for the current event callback termination. Ensures that no callback is being executed when event_del() returns, hence making this function a secure mechanism to access data which is handled in the event callack. Fixes: #236 Fixes: #225 Refs: 6b4b77a Fixes: del_wait (cherry picked from commit 0b4b0efdb8ee710ccae5bad320fc24843fd428e5) --- diff --git a/event.c b/event.c index 918b412d..d2768793 100644 --- a/event.c +++ b/event.c @@ -2780,21 +2780,7 @@ event_del_nolock_(struct event *ev, int blocking) } } - /* If the main thread is currently executing this event's callback, - * and we are not the main thread, then we want to wait until the - * callback is done before we start removing the event. That way, - * when this function returns, it will be safe to free the - * user-supplied argument. */ base = ev->ev_base; -#ifndef EVENT__DISABLE_THREAD_SUPPORT - if (blocking != EVENT_DEL_NOBLOCK && - base->current_event == event_to_event_callback(ev) && - !EVBASE_IN_THREAD(base) && - (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) { - ++base->current_event_waiters; - EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock); - } -#endif EVUTIL_ASSERT(!(ev->ev_flags & ~EVLIST_ALL)); @@ -2841,6 +2827,21 @@ event_del_nolock_(struct event *ev, int blocking) event_debug_note_del_(ev); + /* If the main thread is currently executing this event's callback, + * and we are not the main thread, then we want to wait until the + * callback is done before returning. That way, when this function + * returns, it will be safe to free the user-supplied argument. + */ +#ifndef EVENT__DISABLE_THREAD_SUPPORT + if (blocking != EVENT_DEL_NOBLOCK && + base->current_event == event_to_event_callback(ev) && + !EVBASE_IN_THREAD(base) && + (blocking == EVENT_DEL_BLOCK || !(ev->ev_events & EV_FINALIZE))) { + ++base->current_event_waiters; + EVTHREAD_COND_WAIT(base->current_event_cond, base->th_base_lock); + } +#endif + return (res); }