diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2015-12-25 17:10:06 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2015-12-25 17:10:06 +0000 |
commit | c32643b5982889916dce10eefe3249e1a60d2e18 (patch) | |
tree | f4ecc4df5c040b27da4a47ce5011ccb2d42b22ec | |
parent | 3da7ed0213d7ba6ae3c79fb8cda2f0dd831253ec (diff) |
revert change to call kevent immediately.
tcpbench (at a minimum) relies on the old behavior of changes all happening
after all event handlers run. in particular, it resets the event for the
listening socket *before* calling accept(), when it is still readable.
kevent then (correctly) says it is readable on the next go through the loop.
silly, subtle, and stupid.
problem reported by kettenis
-rw-r--r-- | lib/libevent/kqueue.c | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/lib/libevent/kqueue.c b/lib/libevent/kqueue.c index 04ba3289af3..82a0c7e6f17 100644 --- a/lib/libevent/kqueue.c +++ b/lib/libevent/kqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kqueue.c,v 1.37 2015/12/16 20:12:31 tedu Exp $ */ +/* $OpenBSD: kqueue.c,v 1.38 2015/12/25 17:10:05 tedu Exp $ */ /* * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> @@ -51,6 +51,8 @@ #define NEVENT 64 struct kqop { + struct kevent *changes; + int nchanges; struct kevent *events; struct event_list evsigevents[NSIG]; int nevents; @@ -62,6 +64,7 @@ static void *kq_init (struct event_base *); static int kq_add (void *, struct event *); static int kq_del (void *, struct event *); static int kq_dispatch (struct event_base *, void *, struct timeval *); +static int kq_insert (struct kqop *, struct kevent *); static void kq_dealloc (struct event_base *, void *); const struct eventop kqops = { @@ -100,8 +103,14 @@ kq_init(struct event_base *base) kqueueop->pid = getpid(); /* Initalize fields */ + kqueueop->changes = calloc(NEVENT, sizeof(struct kevent)); + if (kqueueop->changes == NULL) { + free (kqueueop); + return (NULL); + } kqueueop->events = calloc(NEVENT, sizeof(struct kevent)); if (kqueueop->events == NULL) { + free (kqueueop->changes); free (kqueueop); return (NULL); } @@ -115,6 +124,51 @@ kq_init(struct event_base *base) return (kqueueop); } +static int +kq_insert(struct kqop *kqop, struct kevent *kev) +{ + int nevents = kqop->nevents; + + if (kqop->nchanges == nevents) { + struct kevent *newchange; + struct kevent *newresult; + + nevents *= 2; + + newchange = reallocarray(kqop->changes, + nevents, sizeof(struct kevent)); + if (newchange == NULL) { + event_warn("%s: malloc", __func__); + return (-1); + } + kqop->changes = newchange; + + newresult = reallocarray(kqop->events, + nevents, sizeof(struct kevent)); + + /* + * If we fail, we don't have to worry about freeing, + * the next realloc will pick it up. + */ + if (newresult == NULL) { + event_warn("%s: malloc", __func__); + return (-1); + } + kqop->events = newresult; + + kqop->nevents = nevents; + } + + memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent)); + + event_debug(("%s: fd %d %s%s", + __func__, (int)kev->ident, + kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE", + kev->flags == EV_DELETE ? " (del)" : "")); + + return (0); +} + static void kq_sighandler(int sig) { @@ -125,6 +179,7 @@ static int kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) { struct kqop *kqop = arg; + struct kevent *changes = kqop->changes; struct kevent *events = kqop->events; struct event *ev; struct timespec ts, *ts_p = NULL; @@ -135,7 +190,9 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv) ts_p = &ts; } - res = kevent(kqop->kq, NULL, 0, events, kqop->nevents, ts_p); + res = kevent(kqop->kq, changes, kqop->nchanges, + events, kqop->nevents, ts_p); + kqop->nchanges = 0; if (res == -1) { if (errno != EINTR) { event_warn("kevent"); @@ -269,7 +326,7 @@ kq_add(void *arg, struct event *ev) kev.flags |= EV_ONESHOT; kev.udata = ev; - if (kevent(kqop->kq, &kev, 1, NULL, 0, NULL) == -1) + if (kq_insert(kqop, &kev) == -1) return (-1); ev->ev_flags |= EVLIST_X_KQINKERNEL; @@ -284,7 +341,7 @@ kq_add(void *arg, struct event *ev) kev.flags |= EV_ONESHOT; kev.udata = ev; - if (kevent(kqop->kq, &kev, 1, NULL, 0, NULL) == -1) + if (kq_insert(kqop, &kev) == -1) return (-1); ev->ev_flags |= EVLIST_X_KQINKERNEL; @@ -335,7 +392,7 @@ kq_del(void *arg, struct event *ev) kev.filter = EVFILT_READ; kev.flags = EV_DELETE; - if (kevent(kqop->kq, &kev, 1, NULL, 0, NULL) == -1) + if (kq_insert(kqop, &kev) == -1) return (-1); ev->ev_flags &= ~EVLIST_X_KQINKERNEL; @@ -347,7 +404,7 @@ kq_del(void *arg, struct event *ev) kev.filter = EVFILT_WRITE; kev.flags = EV_DELETE; - if (kevent(kqop->kq, &kev, 1, NULL, 0, NULL) == -1) + if (kq_insert(kqop, &kev) == -1) return (-1); ev->ev_flags &= ~EVLIST_X_KQINKERNEL; @@ -363,6 +420,8 @@ kq_dealloc(struct event_base *base, void *arg) evsignal_dealloc(base); + if (kqop->changes) + free(kqop->changes); if (kqop->events) free(kqop->events); if (kqop->kq >= 0 && kqop->pid == getpid()) |