mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-17 08:17:42 -04:00
Always run pending finalizers when event_base_free() is called
There was actually a bug in the original version of this: it tried to run the finalizers after (potentially) setting current_base to NULL; but those finalizers could themselves (potentially) be invoking stuff that needed to know about the current event_base. So the right time to do it is _before_ clearing current_base.
This commit is contained in:
parent
02fbf68770
commit
e9ebef83a0
80
event.c
80
event.c
@ -706,8 +706,46 @@ event_base_stop_iocp_(struct event_base *base)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
event_base_free(struct event_base *base)
|
||||
static int
|
||||
event_base_cancel_single_callback_(struct event_base *base,
|
||||
struct event_callback *evcb,
|
||||
int run_finalizers)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (evcb->evcb_flags & EVLIST_INIT) {
|
||||
struct event *ev = event_callback_to_event(evcb);
|
||||
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
|
||||
event_del_(ev, EVENT_DEL_EVEN_IF_FINALIZING);
|
||||
result = 1;
|
||||
}
|
||||
} else {
|
||||
event_callback_cancel_nolock_(base, evcb, 1);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (run_finalizers && (evcb->evcb_flags & EVLIST_FINALIZING)) {
|
||||
switch (evcb->evcb_closure) {
|
||||
case EV_CLOSURE_EVENT_FINALIZE:
|
||||
case EV_CLOSURE_EVENT_FINALIZE_FREE: {
|
||||
struct event *ev = event_callback_to_event(evcb);
|
||||
ev->ev_evcallback.evcb_cb_union.evcb_evfinalize(ev, ev->ev_arg);
|
||||
if (evcb->evcb_closure == EV_CLOSURE_EVENT_FINALIZE_FREE)
|
||||
mm_free(ev);
|
||||
break;
|
||||
}
|
||||
case EV_CLOSURE_CB_FINALIZE:
|
||||
evcb->evcb_cb_union.evcb_cbfinalize(evcb, evcb->evcb_arg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
event_base_free_(struct event_base *base, int run_finalizers)
|
||||
{
|
||||
int i, n_deleted=0;
|
||||
struct event *ev;
|
||||
@ -718,9 +756,6 @@ event_base_free(struct event_base *base)
|
||||
* made it with event_init and forgot to hold a reference to it. */
|
||||
if (base == NULL && current_base)
|
||||
base = current_base;
|
||||
/* If we're freeing current_base, there won't be a current_base. */
|
||||
if (base == current_base)
|
||||
current_base = NULL;
|
||||
/* Don't actually free NULL. */
|
||||
if (base == NULL) {
|
||||
event_warnx("%s: no base to free", __func__);
|
||||
@ -773,30 +808,14 @@ event_base_free(struct event_base *base)
|
||||
struct event_callback *evcb, *next;
|
||||
for (evcb = TAILQ_FIRST(&base->activequeues[i]); evcb; ) {
|
||||
next = TAILQ_NEXT(evcb, evcb_active_next);
|
||||
if (evcb->evcb_flags & EVLIST_INIT) {
|
||||
ev = event_callback_to_event(evcb);
|
||||
if (!(ev->ev_flags & EVLIST_INTERNAL)) {
|
||||
event_del_(ev, EVENT_DEL_EVEN_IF_FINALIZING);
|
||||
++n_deleted;
|
||||
}
|
||||
} else {
|
||||
event_callback_cancel_nolock_(base, evcb, 1);
|
||||
++n_deleted;
|
||||
}
|
||||
n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
|
||||
evcb = next;
|
||||
}
|
||||
}
|
||||
{
|
||||
struct event_callback *evcb;
|
||||
while ((evcb = TAILQ_FIRST(&base->active_later_queue))) {
|
||||
if (evcb->evcb_flags & EVLIST_INIT) {
|
||||
ev = event_callback_to_event(evcb);
|
||||
event_del(ev);
|
||||
++n_deleted;
|
||||
} else {
|
||||
event_callback_cancel_nolock_(base, evcb, 1);
|
||||
++n_deleted;
|
||||
}
|
||||
n_deleted += event_base_cancel_single_callback_(base, evcb, run_finalizers);
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,9 +848,24 @@ event_base_free(struct event_base *base)
|
||||
EVTHREAD_FREE_LOCK(base->th_base_lock, 0);
|
||||
EVTHREAD_FREE_COND(base->current_event_cond);
|
||||
|
||||
/* If we're freeing current_base, there won't be a current_base. */
|
||||
if (base == current_base)
|
||||
current_base = NULL;
|
||||
mm_free(base);
|
||||
}
|
||||
|
||||
void
|
||||
event_base_free_nofinalize(struct event_base *base)
|
||||
{
|
||||
event_base_free_(base, 0);
|
||||
}
|
||||
|
||||
void
|
||||
event_base_free(struct event_base *base)
|
||||
{
|
||||
event_base_free_(base, 1);
|
||||
}
|
||||
|
||||
/* Fake eventop; used to disable the backend temporarily inside event_reinit
|
||||
* so that we can call event_del() on an event without telling the backend.
|
||||
*/
|
||||
|
@ -599,10 +599,14 @@ struct event_base *event_base_new_with_config(const struct event_config *);
|
||||
Note that this function will not close any fds or free any memory passed
|
||||
to event_new as the argument to callback.
|
||||
|
||||
|
||||
@param eb an event_base to be freed
|
||||
*/
|
||||
void event_base_free(struct event_base *);
|
||||
|
||||
/** DOCUMENT */
|
||||
void event_base_free_nofinalize(struct event_base *);
|
||||
|
||||
/** @name Log severities
|
||||
*/
|
||||
/**@{*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user