From f9db33d15dac13e98db4d98b07ed0e404897a55b Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 9 Apr 2010 19:43:54 -0400 Subject: [PATCH 1/4] Add LIST_ delaration to event_struct.h to supplment TAILQ_ Generally, LIST_ can be a little faster than TAILQ_ for most operations. We only need to use TAILQ_ when we care about traversing lists from tail-to-head, or we need to be able to add items to the end of the list. --- include/event2/event_struct.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/event2/event_struct.h b/include/event2/event_struct.h index 83ac2232..9d7111b4 100644 --- a/include/event2/event_struct.h +++ b/include/event2/event_struct.h @@ -69,6 +69,16 @@ struct { \ } #endif /* !TAILQ_ENTRY */ +/* Fix so that people don't have to run with */ +#ifndef LIST_ENTRY +#define _EVENT_DEFINED_LISTENTRY +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} +#endif /* !TAILQ_ENTRY */ + struct event_base; struct event { TAILQ_ENTRY (event) (ev_active_next); @@ -131,6 +141,14 @@ TAILQ_HEAD (event_list, event); TAILQ_HEAD (evkeyvalq, evkeyval); #endif /* _EVENT_DEFINED_TQENTRY */ +#ifdef _EVENT_DEFINED_LISTENTRY +#undef LIST_ENTRY +struct event_dlist; +#undef _EVENT_DEFINED_LISTENTRY +#else +LIST_HEAD (event_dlist, event); +#endif /* _EVENT_DEFINED_LISTENTRY */ + #ifdef __cplusplus } #endif From 6494772e32017b27037ef1f6fc849abbf3d1c9f2 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 9 Apr 2010 19:54:21 -0400 Subject: [PATCH 2/4] Use LIST rather than TAILQ for evmap_io and evmap_signal These structures used TAILQ for the lists of events waiting on a single fd or signal. But order doesn't matter for these lists; only the order of the active events lists actually matters. --- evmap.c | 26 +++++++++++++------------- include/event2/event_struct.h | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/evmap.c b/evmap.c index b11ec3c9..35147782 100644 --- a/evmap.c +++ b/evmap.c @@ -55,7 +55,7 @@ write on a given fd, and the number of each. */ struct evmap_io { - struct event_list events; + struct event_dlist events; ev_uint16_t nread; ev_uint16_t nwrite; }; @@ -63,7 +63,7 @@ struct evmap_io { /* An entry for an evmap_signal list: notes all the events that want to know when a signal triggers. */ struct evmap_signal { - struct event_list events; + struct event_dlist events; }; /* On some platforms, fds start at 0 and increment by 1 as they are @@ -248,7 +248,7 @@ evmap_signal_clear(struct event_signal_map *ctx) static void evmap_io_init(struct evmap_io *entry) { - TAILQ_INIT(&entry->events); + LIST_INIT(&entry->events); entry->nread = 0; entry->nwrite = 0; } @@ -314,7 +314,7 @@ evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev) ctx->nread = (ev_uint16_t) nread; ctx->nwrite = (ev_uint16_t) nwrite; - TAILQ_INSERT_TAIL(&ctx->events, ev, ev_io_next); + LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next); return (retval); } @@ -370,7 +370,7 @@ evmap_io_del(struct event_base *base, evutil_socket_t fd, struct event *ev) ctx->nread = nread; ctx->nwrite = nwrite; - TAILQ_REMOVE(&ctx->events, ev, ev_io_next); + LIST_REMOVE(ev, ev_io_next); return (retval); } @@ -388,7 +388,7 @@ evmap_io_active(struct event_base *base, evutil_socket_t fd, short events) GET_IO_SLOT(ctx, io, fd, evmap_io); EVUTIL_ASSERT(ctx); - TAILQ_FOREACH(ev, &ctx->events, ev_io_next) { + LIST_FOREACH(ev, &ctx->events, ev_io_next) { if (ev->ev_events & events) event_active_nolock(ev, ev->ev_events & events, 1); } @@ -399,7 +399,7 @@ evmap_io_active(struct event_base *base, evutil_socket_t fd, short events) static void evmap_signal_init(struct evmap_signal *entry) { - TAILQ_INIT(&entry->events); + LIST_INIT(&entry->events); } @@ -418,13 +418,13 @@ evmap_signal_add(struct event_base *base, int sig, struct event *ev) GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init, base->evsigsel->fdinfo_len); - if (TAILQ_EMPTY(&ctx->events)) { + if (LIST_EMPTY(&ctx->events)) { if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } - TAILQ_INSERT_TAIL(&ctx->events, ev, ev_signal_next); + LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next); return (1); } @@ -441,13 +441,13 @@ evmap_signal_del(struct event_base *base, int sig, struct event *ev) GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); - if (TAILQ_FIRST(&ctx->events) == TAILQ_LAST(&ctx->events, event_list)) { + LIST_REMOVE(ev, ev_signal_next); + + if (LIST_FIRST(&ctx->events) == NULL) { if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) return (-1); } - TAILQ_REMOVE(&ctx->events, ev, ev_signal_next); - return (1); } @@ -461,7 +461,7 @@ evmap_signal_active(struct event_base *base, evutil_socket_t sig, int ncalls) EVUTIL_ASSERT(sig < map->nentries); GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); - TAILQ_FOREACH(ev, &ctx->events, ev_signal_next) + LIST_FOREACH(ev, &ctx->events, ev_signal_next) event_active_nolock(ev, EV_SIGNAL, ncalls); } diff --git a/include/event2/event_struct.h b/include/event2/event_struct.h index 9d7111b4..712dda0e 100644 --- a/include/event2/event_struct.h +++ b/include/event2/event_struct.h @@ -95,13 +95,13 @@ struct event { union { /* used for io events */ struct { - TAILQ_ENTRY (event) (ev_io_next); + LIST_ENTRY (event) (ev_io_next); struct timeval ev_timeout; } ev_io; /* used by signal events */ struct { - TAILQ_ENTRY (event) (ev_signal_next); + LIST_ENTRY (event) (ev_signal_next); short ev_ncalls; /* Allows deletes in callback */ short *ev_pncalls; From d313c29349dc15f11aba7f6f6936d0118546e5af Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 9 Apr 2010 20:04:24 -0400 Subject: [PATCH 3/4] Use LIST rather than TAILQ for evbuffer callbacks There's no reason to traverse these out-of-order, and we never defined the order that you'd get your callbacks on an evbuffer if you happened to add more than one. --- buffer.c | 24 ++++++++++++------------ buffer_iocp.c | 2 +- evbuffer-internal.h | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/buffer.c b/buffer.c index 14108884..b7c3db9b 100644 --- a/buffer.c +++ b/buffer.c @@ -302,7 +302,7 @@ evbuffer_new(void) if (buffer == NULL) return (NULL); - TAILQ_INIT(&buffer->callbacks); + LIST_INIT(&buffer->callbacks); buffer->refcnt = 1; buffer->last_with_datap = &buffer->first; @@ -393,7 +393,7 @@ evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred) ASSERT_EVBUFFER_LOCKED(buffer); - if (TAILQ_EMPTY(&buffer->callbacks)) { + if (LIST_EMPTY(&buffer->callbacks)) { buffer->n_add_for_cb = buffer->n_del_for_cb = 0; return; } @@ -408,12 +408,12 @@ evbuffer_run_callbacks(struct evbuffer *buffer, int running_deferred) buffer->n_add_for_cb = 0; buffer->n_del_for_cb = 0; } - for (cbent = TAILQ_FIRST(&buffer->callbacks); - cbent != TAILQ_END(&buffer->callbacks); + for (cbent = LIST_FIRST(&buffer->callbacks); + cbent != LIST_END(&buffer->callbacks); cbent = next) { /* Get the 'next' pointer now in case this callback decides * to remove itself or something. */ - next = TAILQ_NEXT(cbent, next); + next = LIST_NEXT(cbent, next); if ((cbent->flags & mask) != masked_val) continue; @@ -463,9 +463,9 @@ evbuffer_remove_all_callbacks(struct evbuffer *buffer) { struct evbuffer_cb_entry *cbent; - while ((cbent = TAILQ_FIRST(&buffer->callbacks))) { - TAILQ_REMOVE(&buffer->callbacks, cbent, next); - mm_free(cbent); + while ((cbent = LIST_FIRST(&buffer->callbacks))) { + LIST_REMOVE(cbent, next); + mm_free(cbent); } } @@ -2631,7 +2631,7 @@ evbuffer_setcb(struct evbuffer *buffer, evbuffer_cb cb, void *cbarg) { EVBUFFER_LOCK(buffer); - if (!TAILQ_EMPTY(&buffer->callbacks)) + if (!LIST_EMPTY(&buffer->callbacks)) evbuffer_remove_all_callbacks(buffer); if (cb) { @@ -2653,7 +2653,7 @@ evbuffer_add_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg) e->cb.cb_func = cb; e->cbarg = cbarg; e->flags = EVBUFFER_CB_ENABLED; - TAILQ_INSERT_HEAD(&buffer->callbacks, e, next); + LIST_INSERT_HEAD(&buffer->callbacks, e, next); EVBUFFER_UNLOCK(buffer); return e; } @@ -2663,7 +2663,7 @@ evbuffer_remove_cb_entry(struct evbuffer *buffer, struct evbuffer_cb_entry *ent) { EVBUFFER_LOCK(buffer); - TAILQ_REMOVE(&buffer->callbacks, ent, next); + LIST_REMOVE(ent, next); EVBUFFER_UNLOCK(buffer); mm_free(ent); return 0; @@ -2675,7 +2675,7 @@ evbuffer_remove_cb(struct evbuffer *buffer, evbuffer_cb_func cb, void *cbarg) struct evbuffer_cb_entry *cbent; int result = -1; EVBUFFER_LOCK(buffer); - TAILQ_FOREACH(cbent, &buffer->callbacks, next) { + LIST_FOREACH(cbent, &buffer->callbacks, next) { if (cb == cbent->cb.cb_func && cbarg == cbent->cbarg) { result = evbuffer_remove_cb_entry(buffer, cbent); goto done; diff --git a/buffer_iocp.c b/buffer_iocp.c index 6983a6ac..7e80d5fb 100644 --- a/buffer_iocp.c +++ b/buffer_iocp.c @@ -146,7 +146,7 @@ evbuffer_overlapped_new(evutil_socket_t fd) evo = mm_calloc(1, sizeof(struct evbuffer_overlapped)); - TAILQ_INIT(&evo->buffer.callbacks); + LIST_INIT(&evo->buffer.callbacks); evo->buffer.refcnt = 1; evo->buffer.is_overlapped = 1; diff --git a/evbuffer-internal.h b/evbuffer-internal.h index 01f5703a..61efe51b 100644 --- a/evbuffer-internal.h +++ b/evbuffer-internal.h @@ -59,7 +59,7 @@ extern "C" { * when bytes are added to or removed from the evbuffer. */ struct evbuffer_cb_entry { /** Structures to implement a doubly-linked queue of callbacks */ - TAILQ_ENTRY(evbuffer_cb_entry) next; + LIST_ENTRY(evbuffer_cb_entry) next; /** The callback function to invoke when this callback is called. If EVBUFFER_CB_OBSOLETE is set in flags, the cb_obsolete field is valid; otherwise, cb_func is valid. */ @@ -144,7 +144,7 @@ struct evbuffer { struct deferred_cb deferred; /** A doubly-linked-list of callback functions */ - TAILQ_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks; + LIST_HEAD(evbuffer_cb_queue, evbuffer_cb_entry) callbacks; /** The parent bufferevent object this evbuffer belongs to. * NULL if the evbuffer stands alone. */ From 974d004eea27f138c468a278e665db38e52cff53 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 9 Apr 2010 20:05:12 -0400 Subject: [PATCH 4/4] Use LIST rather than TAILQ for bufferevent_rate_limit_group members Once again, there's no reason to keep these lists in the order we were keeping them in. Every time we needed to traverse them for any important purpose, we started at a random point anyway. --- bufferevent-internal.h | 4 ++-- bufferevent_ratelim.c | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bufferevent-internal.h b/bufferevent-internal.h index 1b56c432..c7f5109c 100644 --- a/bufferevent-internal.h +++ b/bufferevent-internal.h @@ -59,7 +59,7 @@ extern "C" { struct bufferevent_rate_limit_group { /** List of all members in the group */ - TAILQ_HEAD(rlim_group_member_list, bufferevent_private) members; + LIST_HEAD(rlim_group_member_list, bufferevent_private) members; /** Current limits for the group. */ struct ev_token_bucket rate_limit; struct ev_token_bucket_cfg rate_limit_cfg; @@ -108,7 +108,7 @@ struct bufferevent_rate_limit { * * Note that this field is supposed to be protected by the group * lock */ - TAILQ_ENTRY(bufferevent_private) next_in_group; + LIST_ENTRY(bufferevent_private) next_in_group; /** The rate-limiting group for this bufferevent, or NULL if it is * only rate-limited on its own. */ struct bufferevent_rate_limit_group *group; diff --git a/bufferevent_ratelim.c b/bufferevent_ratelim.c index d32f63b3..78d0c430 100644 --- a/bufferevent_ratelim.c +++ b/bufferevent_ratelim.c @@ -339,7 +339,7 @@ _bev_group_suspend_reading(struct bufferevent_rate_limit_group *g) bufferevent, it will find out later when it looks at its limit and sees that its group is suspended. */ - TAILQ_FOREACH(bev, &g->members, rate_limiting->next_in_group) { + LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) { if (EVLOCK_TRY_LOCK(bev->lock)) { bufferevent_suspend_read(&bev->bev, BEV_SUSPEND_BW_GROUP); @@ -357,7 +357,7 @@ _bev_group_suspend_writing(struct bufferevent_rate_limit_group *g) struct bufferevent_private *bev; g->write_suspended = 1; g->pending_unsuspend_write = 0; - TAILQ_FOREACH(bev, &g->members, rate_limiting->next_in_group) { + LIST_FOREACH(bev, &g->members, rate_limiting->next_in_group) { if (EVLOCK_TRY_LOCK(bev->lock)) { bufferevent_suspend_write(&bev->bev, BEV_SUSPEND_BW_GROUP); @@ -429,13 +429,13 @@ _bev_group_random_element(struct bufferevent_rate_limit_group *group) if (!group->n_members) return NULL; - EVUTIL_ASSERT(! TAILQ_EMPTY(&group->members)); + EVUTIL_ASSERT(! LIST_EMPTY(&group->members)); which = _evutil_weakrand() % group->n_members; - bev = TAILQ_FIRST(&group->members); + bev = LIST_FIRST(&group->members); while (which--) - bev = TAILQ_NEXT(bev, rate_limiting->next_in_group); + bev = LIST_NEXT(bev, rate_limiting->next_in_group); return bev; } @@ -450,12 +450,12 @@ _bev_group_random_element(struct bufferevent_rate_limit_group *group) #define FOREACH_RANDOM_ORDER(block) \ do { \ first = _bev_group_random_element(g); \ - for (bev = first; bev != TAILQ_END(&g->members); \ - bev = TAILQ_NEXT(bev, rate_limiting->next_in_group)) { \ + for (bev = first; bev != LIST_END(&g->members); \ + bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \ block ; \ } \ - for (bev = TAILQ_FIRST(&g->members); bev && bev != first; \ - bev = TAILQ_NEXT(bev, rate_limiting->next_in_group)) { \ + for (bev = LIST_FIRST(&g->members); bev && bev != first; \ + bev = LIST_NEXT(bev, rate_limiting->next_in_group)) { \ block ; \ } \ } while (0) @@ -602,7 +602,7 @@ bufferevent_rate_limit_group_new(struct event_base *base, if (!g) return NULL; memcpy(&g->rate_limit_cfg, cfg, sizeof(g->rate_limit_cfg)); - TAILQ_INIT(&g->members); + LIST_INIT(&g->members); ev_token_bucket_init(&g->rate_limit, cfg, tick, 0); @@ -687,7 +687,7 @@ bufferevent_add_to_rate_limit_group(struct bufferevent *bev, LOCK_GROUP(g); bevp->rate_limiting->group = g; ++g->n_members; - TAILQ_INSERT_TAIL(&g->members, bevp, rate_limiting->next_in_group); + LIST_INSERT_HEAD(&g->members, bevp, rate_limiting->next_in_group); rsuspend = g->read_suspended; wsuspend = g->write_suspended; @@ -715,7 +715,7 @@ bufferevent_remove_from_rate_limit_group(struct bufferevent *bev) LOCK_GROUP(g); bevp->rate_limiting->group = NULL; --g->n_members; - TAILQ_REMOVE(&g->members, bevp, rate_limiting->next_in_group); + LIST_REMOVE(bevp, rate_limiting->next_in_group); UNLOCK_GROUP(g); } bufferevent_unsuspend_read(bev, BEV_SUSPEND_BW_GROUP);