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 /lib | |
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
Diffstat (limited to 'lib')
-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()) |