Merge branch '21_event_cleanup_v3'

This commit is contained in:
Nick Mathewson 2012-11-16 10:13:15 -05:00
commit 0a396a02ba
3 changed files with 44 additions and 18 deletions

View File

@ -179,6 +179,15 @@ extern int event_debug_mode_on_;
TAILQ_HEAD(evcallback_list, event_callback); 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 { struct event_base {
/** Function pointers and other data to describe this event_base's /** Function pointers and other data to describe this event_base's
* backend. */ * backend. */
@ -310,6 +319,10 @@ struct event_base {
/** Saved seed for weak random number generator. Some backends use /** Saved seed for weak random number generator. Some backends use
* this to produce fairness among sockets. Protected by th_base_lock. */ * this to produce fairness among sockets. Protected by th_base_lock. */
struct evutil_weakrand_state weakrand_seed; 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 { struct event_config_entry {

35
event.c
View File

@ -805,6 +805,12 @@ event_base_free(struct event_base *base)
event_debug(("%s: %d events were still set in base", event_debug(("%s: %d events were still set in base",
__func__, n_deleted)); __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) if (base->evsel != NULL && base->evsel->dealloc != NULL)
base->evsel->dealloc(base); base->evsel->dealloc(base);
@ -1771,22 +1777,18 @@ done:
return (retval); 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, /* One-time callback to implement event_base_once: invokes the user callback,
* then deletes the allocated storage */ * then deletes the allocated storage */
static void static void
event_once_cb(evutil_socket_t fd, short events, void *arg) event_once_cb(evutil_socket_t fd, short events, void *arg)
{ {
struct event_once *eonce = arg; struct event_once *eonce = arg;
struct event_base *base = eonce->ev.ev_base;
(*eonce->cb)(fd, events, eonce->arg); (*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); event_debug_unassign(&eonce->ev);
mm_free(eonce); mm_free(eonce);
} }
@ -1808,6 +1810,7 @@ event_base_once(struct event_base *base, evutil_socket_t fd, short events,
{ {
struct event_once *eonce; struct event_once *eonce;
int res = 0; int res = 0;
int activate = 0;
/* We cannot support signals that just fire once, or persistent /* We cannot support signals that just fire once, or persistent
* events. */ * 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 * don't put it on the timeout queue. This is one
* idiom for scheduling a callback, so let's make * idiom for scheduling a callback, so let's make
* it fast (and order-preserving). */ * it fast (and order-preserving). */
event_active(&eonce->ev, EV_TIMEOUT, 1); activate = 1;
return 0;
} }
} else if (events & (EV_READ|EV_WRITE)) { } else if (events & (EV_READ|EV_WRITE)) {
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); return (-1);
} }
if (res == 0) if (res == 0) {
res = event_add(&eonce->ev, tv); 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) { if (res != 0) {
mm_free(eonce); mm_free(eonce);
return (res); return (res);
} else {
LIST_INSERT_HEAD(&base->once_events, eonce, next_once);
}
EVBASE_RELEASE_LOCK(base, th_base_lock);
} }
return (0); return (0);

View File

@ -1005,9 +1005,11 @@ void event_free(struct event *);
schedules a callback to be called exactly once, and does not require the schedules a callback to be called exactly once, and does not require the
caller to prepare an event structure. caller to prepare an event structure.
Note that in Libevent 2.0 and earlier, if the event is never triggered, Note that in Libevent 2.0 and earlier, if the event is never triggered, the
the internal memory used to hold it will never be freed. This may be internal memory used to hold it will never be freed. In Libevent 2.1,
fixed in a later version of Libevent. 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 base an event_base
@param fd a file descriptor to monitor, or -1 for no fd. @param fd a file descriptor to monitor, or -1 for no fd.