summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2005-06-18 01:52:23 +0000
committerBrad Smith <brad@cvs.openbsd.org>2005-06-18 01:52:23 +0000
commitd6e2399b27e4680a5b1c6b7b93859abf0cadbf41 (patch)
tree21689a02039d22a9d8c83dfb15c24eb525a00abc
parent0cb1eefb1a92308c42327cdf4df7f473db8952d6 (diff)
update to libevent 1.1a; keep local changes
ok grunk@
-rw-r--r--lib/libevent/buffer.c8
-rw-r--r--lib/libevent/event.36
-rw-r--r--lib/libevent/event.h4
-rw-r--r--lib/libevent/kqueue.c26
-rw-r--r--lib/libevent/poll.c244
-rw-r--r--lib/libevent/select.c249
6 files changed, 371 insertions, 166 deletions
diff --git a/lib/libevent/buffer.c b/lib/libevent/buffer.c
index 446f1d9ba2d..379415a7f33 100644
--- a/lib/libevent/buffer.c
+++ b/lib/libevent/buffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.c,v 1.5 2005/05/04 03:17:48 brad Exp $ */
+/* $OpenBSD: buffer.c,v 1.6 2005/06/18 01:52:22 brad Exp $ */
/*
* Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
@@ -186,10 +186,10 @@ evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
char *
evbuffer_readline(struct evbuffer *buffer)
{
- char *data = EVBUFFER_DATA(buffer);
+ u_char *data = EVBUFFER_DATA(buffer);
size_t len = EVBUFFER_LENGTH(buffer);
char *line;
- int i;
+ u_int i;
for (i = 0; i < len; i++) {
if (data[i] == '\r' || data[i] == '\n')
@@ -334,7 +334,7 @@ evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
#endif
#ifdef FIONREAD
- if (ioctl(fd, FIONREAD, &n) == -1)
+ if (ioctl(fd, FIONREAD, &n) == -1 || n == 0)
n = EVBUFFER_MAX_READ;
#endif
if (howmuch < 0 || howmuch > n)
diff --git a/lib/libevent/event.3 b/lib/libevent/event.3
index 25cb2e48eff..4eedc9edcc2 100644
--- a/lib/libevent/event.3
+++ b/lib/libevent/event.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: event.3,v 1.20 2005/05/04 03:17:48 brad Exp $
+.\" $OpenBSD: event.3,v 1.21 2005/06/18 01:52:22 brad Exp $
.\"
.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
.\" All rights reserved.
@@ -196,7 +196,7 @@ After the signal handler sets
.Nm event_dispatch
will execute the callback function to process received signals.
The callback returns 1 when no events are registered any more.
-It can return -1 to indicate an error to the
+It can return \-1 to indicate an error to the
.Nm event
library, causing
.Fn event_dispatch
@@ -366,7 +366,7 @@ The functions
and
.Fn evtimer_pending
are abbreviations for common situations where only a timeout is required.
-The file descriptor passed will be 0, and the event type will be
+The file descriptor passed will be \-1, and the event type will be
.Va EV_TIMEOUT .
.Pp
The functions
diff --git a/lib/libevent/event.h b/lib/libevent/event.h
index 44c3a6391be..2b3332f9fc5 100644
--- a/lib/libevent/event.h
+++ b/lib/libevent/event.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: event.h,v 1.11 2005/05/07 03:07:53 brad Exp $ */
+/* $OpenBSD: event.h,v 1.12 2005/06/18 01:52:22 brad Exp $ */
/*
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
@@ -40,7 +40,7 @@ extern "C" {
typedef unsigned char u_char;
#endif
-#define LIBEVENT_VERSION "1.0e"
+#define LIBEVENT_VERSION "1.1a"
#define EVLIST_TIMEOUT 0x01
#define EVLIST_INSERTED 0x02
diff --git a/lib/libevent/kqueue.c b/lib/libevent/kqueue.c
index a1a02ff993b..2bdcf78b215 100644
--- a/lib/libevent/kqueue.c
+++ b/lib/libevent/kqueue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kqueue.c,v 1.16 2005/05/04 03:17:48 brad Exp $ */
+/* $OpenBSD: kqueue.c,v 1.17 2005/06/18 01:52:22 brad Exp $ */
/*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
@@ -122,6 +122,27 @@ kq_init(void)
}
kqueueop->nevents = NEVENT;
+ /* Check for Mac OS X kqueue bug. */
+ kqueueop->changes[0].ident = -1;
+ kqueueop->changes[0].filter = EVFILT_READ;
+ kqueueop->changes[0].flags = EV_ADD;
+ /*
+ * If kqueue works, then kevent will succeed, and it will
+ * stick an error in events[0]. If kqueue is broken, then
+ * kevent will fail.
+ */
+ if (kevent(kq,
+ kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
+ kqueueop->events[0].ident != -1 ||
+ kqueueop->events[0].flags != EV_ERROR) {
+ event_warn("%s: detected broken kqueue; not using.", __func__);
+ free(kqueueop->changes);
+ free(kqueueop->events);
+ free(kqueueop);
+ close(kq);
+ return (NULL);
+ }
+
return (kqueueop);
}
@@ -218,11 +239,14 @@ kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
* closed,
* ENOENT when the file discriptor was closed and
* then reopened.
+ * EINVAL for some reasons not understood; EINVAL
+ * should not be returned ever; but FreeBSD does :-\
* An error is also indicated when a callback deletes
* an event we are still processing. In that case
* the data field is set to ENOENT.
*/
if (events[i].data == EBADF ||
+ events[i].data == EINVAL ||
events[i].data == ENOENT)
continue;
errno = events[i].data;
diff --git a/lib/libevent/poll.c b/lib/libevent/poll.c
index 35d5d4525dd..8f691bbae0d 100644
--- a/lib/libevent/poll.c
+++ b/lib/libevent/poll.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: poll.c,v 1.8 2005/05/06 18:22:53 brad Exp $ */
+/* $OpenBSD: poll.c,v 1.9 2005/06/18 01:52:22 brad Exp $ */
/*
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
@@ -45,6 +45,9 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
#include "event.h"
#include "event-internal.h"
@@ -55,6 +58,7 @@ extern volatile sig_atomic_t evsignal_caught;
struct pollop {
int event_count; /* Highest number alloc */
+ int nfds; /* Size of event_* */
int fd_count; /* Size of idxplus1_by_fd */
struct pollfd *event_set;
struct event **event_r_back;
@@ -110,97 +114,52 @@ poll_recalc(struct event_base *base, void *arg, int max)
return (evsignal_recalc(&pop->evsigmask));
}
-int
-poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+#ifdef CHECK_INVARIANTS
+static void
+poll_check_ok(struct pollop *pop)
{
- int res, i, count, fd_count, sec, nfds;
+ int i, idx;
struct event *ev;
- struct pollop *pop = arg;
- int *idxplus1_by_fd;
-
- count = pop->event_count;
- fd_count = pop->fd_count;
- idxplus1_by_fd = pop->idxplus1_by_fd;
- memset(idxplus1_by_fd, 0, sizeof(int)*fd_count);
- nfds = 0;
-
- TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
- struct pollfd *pfd = NULL;
- if (nfds + 1 >= count) {
- if (count < 32)
- count = 32;
- else
- count *= 2;
-
- /* We need more file descriptors */
- pop->event_set = realloc(pop->event_set,
- count * sizeof(struct pollfd));
- if (pop->event_set == NULL) {
- event_warn("realloc");
- return (-1);
- }
- pop->event_r_back = realloc(pop->event_r_back,
- count * sizeof(struct event *));
- pop->event_w_back = realloc(pop->event_w_back,
- count * sizeof(struct event *));
- if (pop->event_r_back == NULL ||
- pop->event_w_back == NULL) {
- event_warn("realloc");
- return (-1);
- }
- pop->event_count = count;
- }
- if (!(ev->ev_events & (EV_READ|EV_WRITE)))
- continue;
- if (ev->ev_fd >= fd_count) {
- int new_count;
- if (fd_count < 32)
- new_count = 32;
- else
- new_count = fd_count * 2;
- while (new_count <= ev->ev_fd)
- new_count *= 2;
- idxplus1_by_fd = pop->idxplus1_by_fd =
- realloc(pop->idxplus1_by_fd, new_count*sizeof(int));
- if (idxplus1_by_fd == NULL) {
- event_warn("realloc");
- return (-1);
- }
- memset(pop->idxplus1_by_fd + fd_count,
- 0, sizeof(int)*(new_count-fd_count));
- fd_count = pop->fd_count = new_count;
- }
- i = idxplus1_by_fd[ev->ev_fd] - 1;
- if (i >= 0) {
- pfd = &pop->event_set[i];
- } else {
- i = nfds++;
- pfd = &pop->event_set[i];
- pop->event_w_back[i] = pop->event_r_back[i] = NULL;
- pfd->events = 0;
- idxplus1_by_fd[ev->ev_fd] = i + 1;
- }
-
- if (ev->ev_events & EV_WRITE) {
- pfd->fd = ev->ev_fd;
- pfd->events |= POLLOUT;
- pfd->revents = 0;
- pop->event_w_back[i] = ev;
+ for (i = 0; i < pop->fd_count; ++i) {
+ idx = pop->idxplus1_by_fd[i]-1;
+ if (idx < 0)
+ continue;
+ assert(pop->event_set[idx].fd == i);
+ if (pop->event_set[idx].events & POLLIN) {
+ ev = pop->event_r_back[idx];
+ assert(ev);
+ assert(ev->ev_events & EV_READ);
+ assert(ev->ev_fd == i);
}
- if (ev->ev_events & EV_READ) {
- pfd->fd = ev->ev_fd;
- pfd->events |= POLLIN;
- pfd->revents = 0;
-
- pop->event_r_back[i] = ev;
+ if (pop->event_set[idx].events & POLLOUT) {
+ ev = pop->event_w_back[idx];
+ assert(ev);
+ assert(ev->ev_events & EV_WRITE);
+ assert(ev->ev_fd == i);
}
}
+ for (i = 0; i < pop->nfds; ++i) {
+ struct pollfd *pfd = &pop->event_set[i];
+ assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
+ }
+}
+#else
+#define poll_check_ok(pop)
+#endif
+
+int
+poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ int res, i, sec, nfds;
+ struct pollop *pop = arg;
if (evsignal_deliver(&pop->evsigmask) == -1)
return (-1);
+ poll_check_ok(pop);
sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+ nfds = pop->nfds;
res = poll(pop->event_set, nfds, sec);
if (evsignal_recalc(&pop->evsigmask) == -1)
@@ -226,13 +185,14 @@ poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
int what = pop->event_set[i].revents;
struct event *r_ev = NULL, *w_ev = NULL;
+ if (!what)
+ continue;
+
res = 0;
/* If the file gets closed notify */
- if (what & POLLHUP)
+ if (what & (POLLHUP|POLLERR))
what |= POLLIN|POLLOUT;
- if (what & POLLERR)
- what |= POLLIN|POLLOUT;
if (what & POLLIN) {
res |= EV_READ;
r_ev = pop->event_r_back[i];
@@ -263,9 +223,79 @@ int
poll_add(void *arg, struct event *ev)
{
struct pollop *pop = arg;
+ struct pollfd *pfd = NULL;
+ int i;
if (ev->ev_events & EV_SIGNAL)
return (evsignal_add(&pop->evsigmask, ev));
+ if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ if (pop->nfds + 1 >= pop->event_count) {
+ if (pop->event_count < 32)
+ pop->event_count = 32;
+ else
+ pop->event_count *= 2;
+
+ /* We need more file descriptors */
+ pop->event_set = realloc(pop->event_set,
+ pop->event_count * sizeof(struct pollfd));
+ if (pop->event_set == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->event_r_back = realloc(pop->event_r_back,
+ pop->event_count * sizeof(struct event *));
+ pop->event_w_back = realloc(pop->event_w_back,
+ pop->event_count * sizeof(struct event *));
+ if (pop->event_r_back == NULL ||
+ pop->event_w_back == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ }
+ if (ev->ev_fd >= pop->fd_count) {
+ int new_count;
+ if (pop->fd_count < 32)
+ new_count = 32;
+ else
+ new_count = pop->fd_count * 2;
+ while (new_count <= ev->ev_fd)
+ new_count *= 2;
+ pop->idxplus1_by_fd =
+ realloc(pop->idxplus1_by_fd, new_count*sizeof(int));
+ if (pop->idxplus1_by_fd == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ memset(pop->idxplus1_by_fd + pop->fd_count,
+ 0, sizeof(int)*(new_count - pop->fd_count));
+ pop->fd_count = new_count;
+ }
+
+ i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+ if (i >= 0) {
+ pfd = &pop->event_set[i];
+ } else {
+ i = pop->nfds++;
+ pfd = &pop->event_set[i];
+ pfd->events = 0;
+ pfd->fd = ev->ev_fd;
+ pop->event_w_back[i] = pop->event_r_back[i] = NULL;
+ pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
+ }
+
+ pfd->revents = 0;
+ if (ev->ev_events & EV_WRITE) {
+ pfd->events |= POLLOUT;
+ pop->event_w_back[i] = ev;
+ }
+ if (ev->ev_events & EV_READ) {
+ pfd->events |= POLLIN;
+ pop->event_r_back[i] = ev;
+ }
+ poll_check_ok(pop);
return (0);
}
@@ -278,9 +308,51 @@ int
poll_del(void *arg, struct event *ev)
{
struct pollop *pop = arg;
+ struct pollfd *pfd = NULL;
+ int i;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(&pop->evsigmask, ev));
+
+ if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+ if (i < 0)
+ return (-1);
- if (!(ev->ev_events & EV_SIGNAL))
+ /* Do we still want to read or write? */
+ pfd = &pop->event_set[i];
+ if (ev->ev_events & EV_READ) {
+ pfd->events &= ~POLLIN;
+ pop->event_r_back[i] = NULL;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ pfd->events &= ~POLLOUT;
+ pop->event_w_back[i] = NULL;
+ }
+ poll_check_ok(pop);
+ if (pfd->events)
+ /* Another event cares about that fd. */
return (0);
- return (evsignal_del(&pop->evsigmask, ev));
+ /* Okay, so we aren't interested in that fd anymore. */
+ pop->idxplus1_by_fd[ev->ev_fd] = 0;
+
+ --pop->nfds;
+ if (i != pop->nfds) {
+ /*
+ * Shift the last pollfd down into the now-unoccupied
+ * position.
+ */
+ memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
+ sizeof(struct pollfd));
+ pop->event_r_back[i] = pop->event_r_back[pop->nfds];
+ pop->event_w_back[i] = pop->event_w_back[pop->nfds];
+ pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
+ }
+
+ poll_check_ok(pop);
+ return (0);
}
diff --git a/lib/libevent/select.c b/lib/libevent/select.c
index d334b902ae6..48ab2e3ec0c 100644
--- a/lib/libevent/select.c
+++ b/lib/libevent/select.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: select.c,v 1.10 2005/05/06 18:22:53 brad Exp $ */
+/* $OpenBSD: select.c,v 1.11 2005/06/18 01:52:22 brad Exp $ */
/*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
@@ -44,6 +44,9 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
#include "event.h"
#include "event-internal.h"
@@ -59,8 +62,12 @@ extern volatile sig_atomic_t evsignal_caught;
struct selectop {
int event_fds; /* Highest fd in fd set */
int event_fdsz;
- fd_set *event_readset;
- fd_set *event_writeset;
+ fd_set *event_readset_in;
+ fd_set *event_writeset_in;
+ fd_set *event_readset_out;
+ fd_set *event_writeset_out;
+ struct event **event_r_by_fd;
+ struct event **event_w_by_fd;
sigset_t evsigmask;
};
@@ -79,6 +86,8 @@ const struct eventop selectops = {
select_dispatch
};
+static int select_resize(struct selectop *sop, int fdsz);
+
void *
select_init(void)
{
@@ -91,11 +100,40 @@ select_init(void)
if (!(sop = calloc(1, sizeof(struct selectop))))
return (NULL);
+ select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
+
evsignal_init(&sop->evsigmask);
return (sop);
}
+#ifdef CHECK_INVARIANTS
+static void
+check_selectop(struct selectop *sop)
+{
+ int i;
+ for (i=0;i<=sop->event_fds;++i) {
+ if (FD_ISSET(i, sop->event_readset_in)) {
+ assert(sop->event_r_by_fd[i]);
+ assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
+ assert(sop->event_r_by_fd[i]->ev_fd == i);
+ } else {
+ assert(! sop->event_r_by_fd[i]);
+ }
+ if (FD_ISSET(i, sop->event_writeset_in)) {
+ assert(sop->event_w_by_fd[i]);
+ assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
+ assert(sop->event_w_by_fd[i]->ev_fd == i);
+ } else {
+ assert(! sop->event_w_by_fd[i]);
+ }
+ }
+
+}
+#else
+#define check_selectop(sop)
+#endif
+
/*
* Called with the highest fd that we know about. If it is 0, completely
* recalculate everything.
@@ -105,41 +143,8 @@ int
select_recalc(struct event_base *base, void *arg, int max)
{
struct selectop *sop = arg;
- fd_set *readset, *writeset;
- struct event *ev;
- int fdsz;
-
- if (sop->event_fds < max)
- sop->event_fds = max;
- if (!sop->event_fds) {
- TAILQ_FOREACH(ev, &base->eventqueue, ev_next)
- if (ev->ev_fd > sop->event_fds)
- sop->event_fds = ev->ev_fd;
- }
-
- fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
- if (fdsz > sop->event_fdsz) {
- if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
- event_warn("malloc");
- return (-1);
- }
-
- if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
- event_warn("malloc");
- free(readset);
- return (-1);
- }
-
- memset((char *)readset + sop->event_fdsz, 0,
- fdsz - sop->event_fdsz);
- memset((char *)writeset + sop->event_fdsz, 0,
- fdsz - sop->event_fdsz);
-
- sop->event_readset = readset;
- sop->event_writeset = writeset;
- sop->event_fdsz = fdsz;
- }
+ check_selectop(sop);
return (evsignal_recalc(&sop->evsigmask));
}
@@ -147,26 +152,23 @@ select_recalc(struct event_base *base, void *arg, int max)
int
select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
- int maxfd, res;
- struct event *ev, *next;
+ int res, i;
struct selectop *sop = arg;
- memset(sop->event_readset, 0, sop->event_fdsz);
- memset(sop->event_writeset, 0, sop->event_fdsz);
+ check_selectop(sop);
- TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
- if (ev->ev_events & EV_WRITE)
- FD_SET(ev->ev_fd, sop->event_writeset);
- if (ev->ev_events & EV_READ)
- FD_SET(ev->ev_fd, sop->event_readset);
- }
+ memcpy(sop->event_readset_out, sop->event_readset_in,
+ sop->event_fdsz);
+ memcpy(sop->event_writeset_out, sop->event_writeset_in,
+ sop->event_fdsz);
if (evsignal_deliver(&sop->evsigmask) == -1)
return (-1);
- res = select(sop->event_fds + 1, sop->event_readset,
- sop->event_writeset, NULL, tv);
+ res = select(sop->event_fds + 1, sop->event_readset_out,
+ sop->event_writeset_out, NULL, tv);
+ check_selectop(sop);
if (evsignal_recalc(&sop->evsigmask) == -1)
return (-1);
@@ -183,32 +185,94 @@ select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
event_debug(("%s: select reports %d", __func__, res));
- maxfd = 0;
- for (ev = TAILQ_FIRST(&base->eventqueue); ev != NULL; ev = next) {
- next = TAILQ_NEXT(ev, ev_next);
-
+ check_selectop(sop);
+ for (i = 0; i <= sop->event_fds; ++i) {
+ struct event *r_ev = NULL, *w_ev = NULL;
res = 0;
- if (FD_ISSET(ev->ev_fd, sop->event_readset))
+ if (FD_ISSET(i, sop->event_readset_out)) {
+ r_ev = sop->event_r_by_fd[i];
res |= EV_READ;
- if (FD_ISSET(ev->ev_fd, sop->event_writeset))
+ }
+ if (FD_ISSET(i, sop->event_writeset_out)) {
+ w_ev = sop->event_w_by_fd[i];
res |= EV_WRITE;
- res &= ev->ev_events;
-
- if (res) {
- if (!(ev->ev_events & EV_PERSIST))
- event_del(ev);
- else if (ev->ev_fd > maxfd)
- maxfd = ev->ev_fd;
- event_active(ev, res, 1);
- } else if (ev->ev_fd > maxfd)
- maxfd = ev->ev_fd;
+ }
+ if (r_ev && (res & r_ev->ev_events)) {
+ if (!(r_ev->ev_events & EV_PERSIST))
+ event_del(r_ev);
+ event_active(r_ev, res & r_ev->ev_events, 1);
+ }
+ if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
+ if (!(w_ev->ev_events & EV_PERSIST))
+ event_del(w_ev);
+ event_active(w_ev, res & w_ev->ev_events, 1);
+ }
}
+ check_selectop(sop);
- sop->event_fds = maxfd;
+ return (0);
+}
+
+
+static int
+select_resize(struct selectop *sop, int fdsz)
+{
+ int n_events, n_events_old;
+
+ fd_set *readset_in = NULL;
+ fd_set *writeset_in = NULL;
+ fd_set *readset_out = NULL;
+ fd_set *writeset_out = NULL;
+ struct event **r_by_fd = NULL;
+ struct event **w_by_fd = NULL;
+
+ n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
+ n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
+
+ if (sop->event_readset_in)
+ check_selectop(sop);
+
+ if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
+ goto error;
+ sop->event_readset_in = readset_in;
+ if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
+ goto error;
+ sop->event_readset_out = readset_out;
+ if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
+ goto error;
+ sop->event_writeset_in = writeset_in;
+ if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
+ goto error;
+ sop->event_writeset_out = writeset_out;
+ if ((r_by_fd = realloc(sop->event_r_by_fd,
+ n_events*sizeof(struct event*))) == NULL)
+ goto error;
+ sop->event_r_by_fd = r_by_fd;
+ if ((w_by_fd = realloc(sop->event_w_by_fd,
+ n_events * sizeof(struct event*))) == NULL)
+ goto error;
+ sop->event_w_by_fd = w_by_fd;
+
+ memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+ memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+ memset(sop->event_r_by_fd + n_events_old, 0,
+ (n_events-n_events_old) * sizeof(struct event*));
+ memset(sop->event_w_by_fd + n_events_old, 0,
+ (n_events-n_events_old) * sizeof(struct event*));
+
+ sop->event_fdsz = fdsz;
+ check_selectop(sop);
return (0);
+
+ error:
+ event_warn("malloc");
+ return (-1);
}
+
int
select_add(void *arg, struct event *ev)
{
@@ -217,12 +281,40 @@ select_add(void *arg, struct event *ev)
if (ev->ev_events & EV_SIGNAL)
return (evsignal_add(&sop->evsigmask, ev));
- /*
+ check_selectop(sop);
+ /*
* Keep track of the highest fd, so that we can calculate the size
* of the fd_sets for select(2)
*/
- if (sop->event_fds < ev->ev_fd)
+ if (sop->event_fds < ev->ev_fd) {
+ int fdsz = sop->event_fdsz;
+
+ if (fdsz < sizeof(fd_mask))
+ fdsz = sizeof(fd_mask);
+
+ while (fdsz <
+ (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
+ fdsz *= 2;
+
+ if (fdsz != sop->event_fdsz) {
+ if (select_resize(sop, fdsz)) {
+ check_selectop(sop);
+ return (-1);
+ }
+ }
+
sop->event_fds = ev->ev_fd;
+ }
+
+ if (ev->ev_events & EV_READ) {
+ FD_SET(ev->ev_fd, sop->event_readset_in);
+ sop->event_r_by_fd[ev->ev_fd] = ev;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ FD_SET(ev->ev_fd, sop->event_writeset_in);
+ sop->event_w_by_fd[ev->ev_fd] = ev;
+ }
+ check_selectop(sop);
return (0);
}
@@ -236,8 +328,25 @@ select_del(void *arg, struct event *ev)
{
struct selectop *sop = arg;
- if (!(ev->ev_events & EV_SIGNAL))
+ check_selectop(sop);
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(&sop->evsigmask, ev));
+
+ if (sop->event_fds < ev->ev_fd) {
+ check_selectop(sop);
return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ FD_CLR(ev->ev_fd, sop->event_readset_in);
+ sop->event_r_by_fd[ev->ev_fd] = NULL;
+ }
- return (evsignal_del(&sop->evsigmask, ev));
+ if (ev->ev_events & EV_WRITE) {
+ FD_CLR(ev->ev_fd, sop->event_writeset_in);
+ sop->event_w_by_fd[ev->ev_fd] = NULL;
+ }
+
+ check_selectop(sop);
+ return (0);
}