]> granicus.if.org Git - libevent/commitdiff
Return from event_del() after the last event callback termination
authorJosé Luis Millán <jmillan@aliax.net>
Mon, 13 Apr 2015 06:54:52 +0000 (08:54 +0200)
committerAzat Khuzhin <azat@libevent.org>
Sat, 2 Feb 2019 12:13:50 +0000 (15:13 +0300)
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)

event.c

diff --git a/event.c b/event.c
index 918b412df6279ba1f247e645faf9e872facd2cfb..d2768793604b546f7a9d82fd8e9791376fd4fc11 100644 (file)
--- 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);
 }