summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2015-12-25 17:10:06 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2015-12-25 17:10:06 +0000
commitc32643b5982889916dce10eefe3249e1a60d2e18 (patch)
treef4ecc4df5c040b27da4a47ce5011ccb2d42b22ec
parent3da7ed0213d7ba6ae3c79fb8cda2f0dd831253ec (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.c71
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())