mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +08:00
Free dangling event_once objects on event_base_free()
This patch makes us keep event_once objects in a doubly linked list so we can free any once that haven't triggered when we call event_base_free().
This commit is contained in:
parent
1f5a48d1d0
commit
c17dd59191
@ -179,6 +179,15 @@ extern int event_debug_mode_on_;
|
||||
|
||||
TAILQ_HEAD(evcallback_list, event_callback);
|
||||
|
||||
/* Sets up an event for processing once */
|
||||
struct event_once {
|
||||
LIST_ENTRY(event_once) next_once;
|
||||
struct event ev;
|
||||
|
||||
void (*cb)(evutil_socket_t, short, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
struct event_base {
|
||||
/** Function pointers and other data to describe this event_base's
|
||||
* backend. */
|
||||
@ -310,6 +319,10 @@ struct event_base {
|
||||
/** Saved seed for weak random number generator. Some backends use
|
||||
* this to produce fairness among sockets. Protected by th_base_lock. */
|
||||
struct evutil_weakrand_state weakrand_seed;
|
||||
|
||||
/** List of event_onces that have not yet fired. */
|
||||
LIST_HEAD(once_event_list, event_once) once_events;
|
||||
|
||||
};
|
||||
|
||||
struct event_config_entry {
|
||||
|
35
event.c
35
event.c
@ -805,6 +805,12 @@ event_base_free(struct event_base *base)
|
||||
event_debug(("%s: %d events were still set in base",
|
||||
__func__, n_deleted));
|
||||
|
||||
while (LIST_FIRST(&base->once_events)) {
|
||||
struct event_once *eonce = LIST_FIRST(&base->once_events);
|
||||
LIST_REMOVE(eonce, next_once);
|
||||
mm_free(eonce);
|
||||
}
|
||||
|
||||
if (base->evsel != NULL && base->evsel->dealloc != NULL)
|
||||
base->evsel->dealloc(base);
|
||||
|
||||
@ -1771,22 +1777,18 @@ done:
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Sets up an event for processing once */
|
||||
struct event_once {
|
||||
struct event ev;
|
||||
|
||||
void (*cb)(evutil_socket_t, short, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/* One-time callback to implement event_base_once: invokes the user callback,
|
||||
* then deletes the allocated storage */
|
||||
static void
|
||||
event_once_cb(evutil_socket_t fd, short events, void *arg)
|
||||
{
|
||||
struct event_once *eonce = arg;
|
||||
struct event_base *base = eonce->ev.ev_base;
|
||||
|
||||
(*eonce->cb)(fd, events, eonce->arg);
|
||||
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
|
||||
LIST_REMOVE(eonce, next_once);
|
||||
EVBASE_RELEASE_LOCK(base, th_base_lock);
|
||||
event_debug_unassign(&eonce->ev);
|
||||
mm_free(eonce);
|
||||
}
|
||||
@ -1808,6 +1810,7 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
|
||||
{
|
||||
struct event_once *eonce;
|
||||
int res = 0;
|
||||
int activate = 0;
|
||||
|
||||
/* We cannot support signals that just fire once, or persistent
|
||||
* events. */
|
||||
@ -1828,8 +1831,7 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
|
||||
* don't put it on the timeout queue. This is one
|
||||
* idiom for scheduling a callback, so let's make
|
||||
* it fast (and order-preserving). */
|
||||
event_active(&eonce->ev, EV_TIMEOUT, 1);
|
||||
return 0;
|
||||
activate = 1;
|
||||
}
|
||||
} else if (events & (EV_READ|EV_WRITE)) {
|
||||
events &= EV_READ|EV_WRITE;
|
||||
@ -1841,11 +1843,20 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
res = event_add(&eonce->ev, tv);
|
||||
if (res == 0) {
|
||||
EVBASE_ACQUIRE_LOCK(base, th_base_lock);
|
||||
if (activate)
|
||||
event_active_nolock_(&eonce->ev, EV_TIMEOUT, 1);
|
||||
else
|
||||
res = event_add_nolock_(&eonce->ev, tv, 0);
|
||||
|
||||
if (res != 0) {
|
||||
mm_free(eonce);
|
||||
return (res);
|
||||
} else {
|
||||
LIST_INSERT_HEAD(&base->once_events, eonce, next_once);
|
||||
}
|
||||
EVBASE_RELEASE_LOCK(base, th_base_lock);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
@ -1005,9 +1005,11 @@ void event_free(struct event *);
|
||||
schedules a callback to be called exactly once, and does not require the
|
||||
caller to prepare an event structure.
|
||||
|
||||
Note that in Libevent 2.0 and earlier, if the event is never triggered,
|
||||
the internal memory used to hold it will never be freed. This may be
|
||||
fixed in a later version of Libevent.
|
||||
Note that in Libevent 2.0 and earlier, if the event is never triggered, the
|
||||
internal memory used to hold it will never be freed. In Libevent 2.1,
|
||||
the internal memory will get freed by event_base_free() if the event
|
||||
is never triggered. The 'arg' value, however, will not get freed in either
|
||||
case--you'll need to free that on your own if you want it to go away.
|
||||
|
||||
@param base an event_base
|
||||
@param fd a file descriptor to monitor, or -1 for no fd.
|
||||
|
Loading…
x
Reference in New Issue
Block a user