diff options
author | Nick Mathewson <nickm@torproject.org> | 2011-05-03 13:54:57 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2011-05-03 13:54:57 -0400 |
commit | 28317a087e58dceff85a448c22bbbafebed0b6ab (patch) | |
tree | 560f7280284a607abb2f28a801b7ae9a99a14c21 /kqueue.c | |
parent | 9556a7d1f647f61634fb782ae7ba814e5a20535e (diff) | |
download | libevent-28317a087e58dceff85a448c22bbbafebed0b6ab.tar.gz |
Fix a warn-and-fail bug in kqueue by providing kevent() room to report errors
Apparently, kevent fails gracefully if there is not enough space in its
output events array to report every _event_... but it just dies and returns
-1 if there is not enough space to report every _error_.
There are a couple of possible fixes here. One would to handle -1
returns from kevent better by re-growing the array and retrying... but
that seems a little error prone. Instead, I'm just going to say that
the events array must be large enough to handle all the errors.
This patch also adds a unit test designed to make sure that our
many-events-out code works even if not all the events are added at
once.
Diffstat (limited to 'kqueue.c')
-rw-r--r-- | kqueue.c | 46 |
1 files changed, 37 insertions, 9 deletions
@@ -229,6 +229,23 @@ kq_build_changes_list(const struct event_changelist *changelist, } static int +kq_grow_events(struct kqop *kqop, size_t new_size) +{ + struct kevent *newresult; + + newresult = mm_realloc(kqop->events, + new_size * sizeof(struct kevent)); + + if (newresult) { + kqop->events = newresult; + kqop->events_size = new_size; + return 0; + } else { + return -1; + } +} + +static int kq_dispatch(struct event_base *base, struct timeval *tv) { struct kqop *kqop = base->evbase; @@ -255,6 +272,25 @@ kq_dispatch(struct event_base *base, struct timeval *tv) changes = kqop->changes; kqop->changes = NULL; + /* Make sure that 'events' is at least as long as the list of changes: + * otherwise errors in the changes can get reported as a -1 return + * value from kevent() rather than as EV_ERROR events in the events + * array. + * + * (We could instead handle -1 return values from kevent() by + * retrying with a smaller changes array or a larger events array, + * but this approach seems less risky for now.) + */ + if (kqop->events_size < n_changes) { + int new_size = kqop->events_size; + do { + new_size *= 2; + } while (new_size < n_changes); + + kq_grow_events(kqop, new_size); + events = kqop->events; + } + EVBASE_RELEASE_LOCK(base, th_base_lock); res = kevent(kqop->kq, changes, n_changes, @@ -319,17 +355,9 @@ kq_dispatch(struct event_base *base, struct timeval *tv) } if (res == kqop->events_size) { - struct kevent *newresult; - int size = kqop->events_size; /* We used all the events space that we have. Maybe we should make it bigger. */ - size *= 2; - newresult = mm_realloc(kqop->events, - size * sizeof(struct kevent)); - if (newresult) { - kqop->events = newresult; - kqop->events_size = size; - } + kq_grow_events(kqop, kqop->events_size * 2); } return (0); |