summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2005-04-22 00:56:26 +0000
committerBrad Smith <brad@cvs.openbsd.org>2005-04-22 00:56:26 +0000
commit9657663ceec9fe6a3be90c6e4bf3ea973058e65a (patch)
tree671952b73b614f5090d12c04adbb65afd196c12f
parent6ca0465503b5d87bd9dca1cbaadf8de986104de6 (diff)
update to libevent 1.0c; keep local changes
no shared lib so no ABI/API check is necessary thanks to Alexander von Gernler for submitting another diff in an attempt to update libevent and for a use-after-free fix. ok henning@ deraadt@
-rw-r--r--lib/libevent/buffer.c202
-rw-r--r--lib/libevent/err.c97
-rw-r--r--lib/libevent/evbuffer.c18
-rw-r--r--lib/libevent/event-internal.h56
-rw-r--r--lib/libevent/event.c408
-rw-r--r--lib/libevent/event.h59
-rw-r--r--lib/libevent/kqueue.c63
-rw-r--r--lib/libevent/log.c208
-rw-r--r--lib/libevent/log.h45
-rw-r--r--lib/libevent/poll.c46
-rw-r--r--lib/libevent/select.c50
-rw-r--r--lib/libevent/signal.c74
12 files changed, 973 insertions, 353 deletions
diff --git a/lib/libevent/buffer.c b/lib/libevent/buffer.c
index 7755e7f1b53..a072e7d51ee 100644
--- a/lib/libevent/buffer.c
+++ b/lib/libevent/buffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.c,v 1.3 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: buffer.c,v 1.4 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
@@ -27,17 +27,25 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+#ifdef HAVE_VASPRINTF
+/* If we have vasprintf, we need to define this before we include stdio.h. */
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-#include <err.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -64,8 +72,8 @@ evbuffer_new(void)
void
evbuffer_free(struct evbuffer *buffer)
{
- if (buffer->buffer != NULL)
- free(buffer->buffer);
+ if (buffer->orig_buffer != NULL)
+ free(buffer->orig_buffer);
free(buffer);
}
@@ -74,10 +82,42 @@ evbuffer_free(struct evbuffer *buffer)
* the other buffer.
*/
+#define SWAP(x,y) do { \
+ (x)->buffer = (y)->buffer; \
+ (x)->orig_buffer = (y)->orig_buffer; \
+ (x)->misalign = (y)->misalign; \
+ (x)->totallen = (y)->totallen; \
+ (x)->off = (y)->off; \
+} while (0)
+
int
evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
{
int res;
+
+ /* Short cut for better performance */
+ if (outbuf->off == 0) {
+ struct evbuffer tmp;
+ size_t oldoff = inbuf->off;
+
+ /* Swap them directly */
+ SWAP(&tmp, outbuf);
+ SWAP(outbuf, inbuf);
+ SWAP(inbuf, &tmp);
+
+ /*
+ * Optimization comes with a price; we need to notify the
+ * buffer if necessary of the changes. oldoff is the amount
+ * of data that we tranfered from inbuf to outbuf
+ */
+ if (inbuf->off != oldoff && inbuf->cb != NULL)
+ (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
+ if (oldoff && outbuf->cb != NULL)
+ (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
+
+ return (0);
+ }
+
res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
if (res == 0)
evbuffer_drain(inbuf, inbuf->off);
@@ -90,46 +130,113 @@ evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...)
{
int res = -1;
char *msg;
+#ifndef HAVE_VASPRINTF
+ static char buffer[4096];
+#endif
va_list ap;
va_start(ap, fmt);
+#ifdef HAVE_VASPRINTF
if (vasprintf(&msg, fmt, ap) == -1)
goto end;
+#else
+# ifdef WIN32
+ _vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
+ buffer[sizeof(buffer)-1] = '\0';
+# else /* ! WIN32 */
+ vsnprintf(buffer, sizeof(buffer), fmt, ap);
+# endif
+ msg = buffer;
+#endif
res = strlen(msg);
if (evbuffer_add(buf, msg, res) == -1)
res = -1;
+#ifdef HAVE_VASPRINTF
free(msg);
- end:
+end:
+#endif
va_end(ap);
return (res);
}
+/* Reads data from an event buffer and drains the bytes read */
+
int
-evbuffer_add(struct evbuffer *buf, u_char *data, size_t datlen)
+evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
{
- size_t need = buf->off + datlen;
- size_t oldoff = buf->off;
+ int nread = datlen;
+ if (nread >= buf->off)
+ nread = buf->off;
- if (buf->totallen < need) {
+ memcpy(data, buf->buffer, nread);
+ evbuffer_drain(buf, nread);
+
+ return (nread);
+}
+
+/* Adds data to an event buffer */
+
+static inline void
+evbuffer_align(struct evbuffer *buf)
+{
+ memmove(buf->orig_buffer, buf->buffer, buf->off);
+ buf->buffer = buf->orig_buffer;
+ buf->misalign = 0;
+}
+
+/* Expands the available space in the event buffer to at least datlen */
+
+int
+evbuffer_expand(struct evbuffer *buf, size_t datlen)
+{
+ size_t need = buf->misalign + buf->off + datlen;
+
+ /* If we can fit all the data, then we don't have to do anything */
+ if (buf->totallen >= need)
+ return (0);
+
+ /*
+ * If the misalignment fulfills our data needs, we just force an
+ * alignment to happen. Afterwards, we have enough space.
+ */
+ if (buf->misalign >= datlen) {
+ evbuffer_align(buf);
+ } else {
void *newbuf;
- int length = buf->totallen;
+ size_t length = buf->totallen;
if (length < 256)
length = 256;
while (length < need)
length <<= 1;
+ if (buf->orig_buffer != buf->buffer)
+ evbuffer_align(buf);
if ((newbuf = realloc(buf->buffer, length)) == NULL)
return (-1);
- buf->buffer = newbuf;
+ buf->orig_buffer = buf->buffer = newbuf;
buf->totallen = length;
}
+ return (0);
+}
+
+int
+evbuffer_add(struct evbuffer *buf, void *data, size_t datlen)
+{
+ size_t need = buf->misalign + buf->off + datlen;
+ size_t oldoff = buf->off;
+
+ if (buf->totallen < need) {
+ if (evbuffer_expand(buf, datlen) == -1)
+ return (-1);
+ }
+
memcpy(buf->buffer + buf->off, data, datlen);
buf->off += datlen;
@@ -146,10 +253,14 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
if (len >= buf->off) {
buf->off = 0;
+ buf->buffer = buf->orig_buffer;
+ buf->misalign = 0;
goto done;
}
- memmove(buf->buffer, buf->buffer + len, buf->off - len);
+ buf->buffer += len;
+ buf->misalign += len;
+
buf->off -= len;
done:
@@ -159,22 +270,56 @@ evbuffer_drain(struct evbuffer *buf, size_t len)
}
+/*
+ * Reads data from a file descriptor into a buffer.
+ */
+
+#define EVBUFFER_MAX_READ 4096
+
int
-evbuffer_read(struct evbuffer *buffer, int fd, int howmuch)
+evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
{
- u_char inbuf[4096];
- int n;
-
- if (howmuch < 0 || howmuch > sizeof(inbuf))
- howmuch = sizeof(inbuf);
+ u_char *p;
+ size_t oldoff = buf->off;
+ int n = EVBUFFER_MAX_READ;
+#ifdef WIN32
+ DWORD dwBytesRead;
+#endif
+
+#ifdef FIONREAD
+ if (ioctl(fd, FIONREAD, &n) == -1)
+ n = EVBUFFER_MAX_READ;
+#endif
+ if (howmuch < 0 || howmuch > n)
+ howmuch = n;
- n = read(fd, inbuf, howmuch);
+ /* If we don't have FIONREAD, we might waste some space here */
+ if (evbuffer_expand(buf, howmuch) == -1)
+ return (-1);
+
+ /* We can append new data at this point */
+ p = buf->buffer + buf->off;
+
+#ifndef WIN32
+ n = read(fd, p, howmuch);
if (n == -1)
return (-1);
if (n == 0)
return (0);
+#else
+ n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL);
+ if (n == 0)
+ return (-1);
+ if (dwBytesRead == 0)
+ return (0);
+ n = dwBytesRead;
+#endif
- evbuffer_add(buffer, inbuf, n);
+ buf->off += n;
+
+ /* Tell someone about changes in this buffer */
+ if (buf->off != oldoff && buf->cb != NULL)
+ (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
return (n);
}
@@ -183,13 +328,24 @@ int
evbuffer_write(struct evbuffer *buffer, int fd)
{
int n;
+#ifdef WIN32
+ DWORD dwBytesWritten;
+#endif
+#ifndef WIN32
n = write(fd, buffer->buffer, buffer->off);
if (n == -1)
return (-1);
if (n == 0)
return (0);
-
+#else
+ n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL);
+ if (n == 0)
+ return (-1);
+ if (dwBytesWritten == 0)
+ return (0);
+ n = dwBytesWritten;
+#endif
evbuffer_drain(buffer, n);
return (n);
diff --git a/lib/libevent/err.c b/lib/libevent/err.c
deleted file mode 100644
index 4c9862b80a9..00000000000
--- a/lib/libevent/err.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* $OpenBSD: err.c,v 1.5 2005/04/19 08:07:45 deraadt Exp $ */
-
-/*
- * err.c
- *
- * Adapted from OpenBSD libc *err* *warn* code.
- *
- * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
- *
- * Copyright (c) 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-void
-err(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (fmt != NULL) {
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, ": ");
- }
- va_end(ap);
- (void)fprintf(stderr, "%s\n", strerror(errno));
- exit(eval);
-}
-
-void
-warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (fmt != NULL) {
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, ": ");
- }
- va_end(ap);
- (void)fprintf(stderr, "%s\n", strerror(errno));
-}
-
-void
-errx(int eval, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- va_end(ap);
- exit(eval);
-}
-
-void
-warnx(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- if (fmt != NULL)
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- va_end(ap);
-}
-
diff --git a/lib/libevent/evbuffer.c b/lib/libevent/evbuffer.c
index e0cf27202f1..4a2d85303e5 100644
--- a/lib/libevent/evbuffer.c
+++ b/lib/libevent/evbuffer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: evbuffer.c,v 1.3 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: evbuffer.c,v 1.4 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
@@ -37,7 +37,6 @@
#include <sys/time.h>
#endif
-#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -152,7 +151,9 @@ bufferevent_writecb(int fd, short event, void *arg)
if (EVBUFFER_LENGTH(bufev->output)) {
res = evbuffer_write(bufev->output, fd);
if (res == -1) {
- if (errno == EAGAIN || errno == EINTR)
+ if (errno == EAGAIN ||
+ errno == EINTR ||
+ errno == EINPROGRESS)
goto reschedule;
/* error case */
what |= EVBUFFER_ERROR;
@@ -227,6 +228,17 @@ bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
return (bufev);
}
+int
+bufferevent_priority_set(struct bufferevent *bufev, int priority)
+{
+ if (event_priority_set(&bufev->ev_read, priority) == -1)
+ return (-1);
+ if (event_priority_set(&bufev->ev_write, priority) == -1)
+ return (-1);
+
+ return (0);
+}
+
void
bufferevent_free(struct bufferevent *bufev)
{
diff --git a/lib/libevent/event-internal.h b/lib/libevent/event-internal.h
new file mode 100644
index 00000000000..becb6691d52
--- /dev/null
+++ b/lib/libevent/event-internal.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_INTERNAL_H_
+#define _EVENT_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct event_base {
+ const struct eventop *evsel;
+ void *evbase;
+ int event_count; /* counts number of total events */
+ int event_count_active; /* counts number of active events */
+
+ int event_gotterm; /* Set to terminate loop */
+
+ /* active event management */
+ struct event_list **activequeues;
+ int nactivequeues;
+
+ struct event_list eventqueue;
+ struct timeval event_tv;
+
+ RB_HEAD(event_tree, event) timetree;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_INTERNAL_H_ */
diff --git a/lib/libevent/event.c b/lib/libevent/event.c
index 42001fd34fc..0711f7d8a16 100644
--- a/lib/libevent/event.c
+++ b/lib/libevent/event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: event.c,v 1.8 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: event.c,v 1.9 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
@@ -52,17 +52,11 @@
#include <errno.h>
#include <signal.h>
#include <string.h>
-#include <err.h>
#include <assert.h>
-#ifdef USE_LOG
-#include "log.h"
-#else
-#define LOG_DBG(x)
-#define log_error(x) perror(x)
-#endif
-
#include "event.h"
+#include "event-internal.h"
+#include "log.h"
#ifdef HAVE_SELECT
extern const struct eventop selectops;
@@ -79,6 +73,9 @@ extern const struct eventop epollops;
#ifdef HAVE_WORKING_KQUEUE
extern const struct eventop kqops;
#endif
+#ifdef HAVE_DEVPOLL
+extern const struct eventop devpollops;
+#endif
#ifdef WIN32
extern const struct eventop win32ops;
#endif
@@ -91,6 +88,9 @@ const struct eventop *eventops[] = {
#ifdef HAVE_EPOLL
&epollops,
#endif
+#ifdef HAVE_DEVPOLL
+ &devpollops,
+#endif
#ifdef HAVE_RTSIG
&rtsigops,
#endif
@@ -106,26 +106,25 @@ const struct eventop *eventops[] = {
NULL
};
-const struct eventop *evsel;
-void *evbase;
+/* Global state */
+struct event_list signalqueue;
+
+struct event_base *current_base = NULL;
/* Handle signals - This is a deprecated interface */
int (*event_sigcb)(void); /* Signal callback when gotsig is set */
volatile sig_atomic_t event_gotsig; /* Set in signal handler */
-volatile sig_atomic_t event_gotterm; /* Set to terminate loop */
/* Prototypes */
-void event_queue_insert(struct event *, int);
-void event_queue_remove(struct event *, int);
-int event_haveevents(void);
+static void event_queue_insert(struct event_base *, struct event *, int);
+static void event_queue_remove(struct event_base *, struct event *, int);
+static int event_haveevents(struct event_base *);
-static void event_process_active(void);
+static void event_process_active(struct event_base *);
-static RB_HEAD(event_tree, event) timetree;
-static struct event_list activequeue;
-struct event_list signalqueue;
-struct event_list eventqueue;
-static struct timeval event_tv;
+static int timeout_next(struct event_base *, struct timeval *);
+static void timeout_process(struct event_base *);
+static void timeout_correct(struct event_base *, struct timeval *);
static int
compare(struct event *a, struct event *b)
@@ -136,7 +135,7 @@ compare(struct event *a, struct event *b)
return (1);
if (a < b)
return (-1);
- if (a > b)
+ else if (a > b)
return (1);
return (0);
}
@@ -146,55 +145,112 @@ RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
RB_GENERATE(event_tree, event, ev_timeout_node, compare);
-void
+void *
event_init(void)
{
int i;
+ if ((current_base = calloc(1, sizeof(struct event_base))) == NULL)
+ event_err(1, "%s: calloc");
+
event_sigcb = NULL;
event_gotsig = 0;
- gettimeofday(&event_tv, NULL);
+ gettimeofday(&current_base->event_tv, NULL);
- RB_INIT(&timetree);
- TAILQ_INIT(&eventqueue);
- TAILQ_INIT(&activequeue);
+ RB_INIT(&current_base->timetree);
+ TAILQ_INIT(&current_base->eventqueue);
TAILQ_INIT(&signalqueue);
- evbase = NULL;
- for (i = 0; eventops[i] && !evbase; i++) {
- evsel = eventops[i];
+ current_base->evbase = NULL;
+ for (i = 0; eventops[i] && !current_base->evbase; i++) {
+ current_base->evsel = eventops[i];
- evbase = evsel->init();
+ current_base->evbase = current_base->evsel->init();
}
- if (evbase == NULL)
- errx(1, "%s: no event mechanism available", __func__);
+ if (current_base->evbase == NULL)
+ event_errx(1, "%s: no event mechanism available", __func__);
if (!issetugid() && getenv("EVENT_SHOW_METHOD"))
- fprintf(stderr, "libevent using: %s\n", evsel->name);
+ event_msgx("libevent using: %s\n",
+ current_base->evsel->name);
-#if defined(USE_LOG) && defined(USE_DEBUG)
- log_to(stderr);
- log_debug_cmd(LOG_MISC, 80);
-#endif
+ /* allocate a single active event queue */
+ event_base_priority_init(current_base, 1);
+
+ return (current_base);
+}
+
+int
+event_priority_init(int npriorities)
+{
+ return event_base_priority_init(current_base, npriorities);
+}
+
+int
+event_base_priority_init(struct event_base *base, int npriorities)
+{
+ int i;
+
+ if (base->event_count_active)
+ return (-1);
+
+ if (base->nactivequeues && npriorities != base->nactivequeues) {
+ for (i = 0; i < base->nactivequeues; ++i) {
+ free(base->activequeues[i]);
+ }
+ free(base->activequeues);
+ }
+
+ /* Allocate our priority queues */
+ base->nactivequeues = npriorities;
+ base->activequeues = (struct event_list **)calloc(base->nactivequeues,
+ npriorities * sizeof(struct event_list *));
+ if (base->activequeues == NULL)
+ event_err(1, "%s: calloc", __func__);
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ base->activequeues[i] = malloc(sizeof(struct event_list));
+ if (base->activequeues[i] == NULL)
+ event_err(1, "%s: malloc", __func__);
+ TAILQ_INIT(base->activequeues[i]);
+ }
+
+ return (0);
}
int
-event_haveevents(void)
+event_haveevents(struct event_base *base)
{
- return (RB_ROOT(&timetree) || TAILQ_FIRST(&eventqueue) ||
- TAILQ_FIRST(&signalqueue) || TAILQ_FIRST(&activequeue));
+ return (base->event_count > 0);
}
+/*
+ * Active events are stored in priority queues. Lower priorities are always
+ * process before higher priorities. Low priority events can starve high
+ * priority ones.
+ */
+
static void
-event_process_active(void)
+event_process_active(struct event_base *base)
{
struct event *ev;
+ struct event_list *activeq = NULL;
+ int i;
short ncalls;
- for (ev = TAILQ_FIRST(&activequeue); ev;
- ev = TAILQ_FIRST(&activequeue)) {
- event_queue_remove(ev, EVLIST_ACTIVE);
+ if (!base->event_count_active)
+ return;
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
+ activeq = base->activequeues[i];
+ break;
+ }
+ }
+
+ for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
/* Allows deletes to work */
ncalls = ev->ev_ncalls;
@@ -217,36 +273,64 @@ event_dispatch(void)
return (event_loop(0));
}
+int
+event_base_dispatch(struct event_base *event_base)
+{
+ return (event_base_loop(event_base, 0));
+}
+
static void
event_loopexit_cb(int fd, short what, void *arg)
{
- event_gotterm = 1;
+ struct event_base *base = arg;
+ base->event_gotterm = 1;
}
+/* not thread safe */
+
int
event_loopexit(struct timeval *tv)
{
- return (event_once(-1, EV_TIMEOUT, event_loopexit_cb, NULL, tv));
+ return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+ current_base, tv));
}
int
+event_base_loopexit(struct event_base *event_base, struct timeval *tv)
+{
+ return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+ event_base, tv));
+}
+
+/* not thread safe */
+
+int
event_loop(int flags)
{
+ return event_base_loop(current_base, flags);
+}
+
+int
+event_base_loop(struct event_base *base, int flags)
+{
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
struct timeval tv;
int res, done;
/* Calculate the initial events that we are waiting for */
- if (evsel->recalc(evbase, 0) == -1)
+ if (evsel->recalc(base, evbase, 0) == -1)
return (-1);
done = 0;
while (!done) {
/* Terminate the loop if we have been asked to */
- if (event_gotterm) {
- event_gotterm = 0;
+ if (base->event_gotterm) {
+ base->event_gotterm = 0;
break;
}
+ /* You cannot use this interface for multi-threaded apps */
while (event_gotsig) {
event_gotsig = 0;
if (event_sigcb) {
@@ -260,44 +344,45 @@ event_loop(int flags)
/* Check if time is running backwards */
gettimeofday(&tv, NULL);
- if (timercmp(&tv, &event_tv, <)) {
+ if (timercmp(&tv, &base->event_tv, <)) {
struct timeval off;
- LOG_DBG((LOG_MISC, 10,
- "%s: time is running backwards, corrected",
+ event_debug(("%s: time is running backwards, corrected",
__func__));
-
- timersub(&event_tv, &tv, &off);
- timeout_correct(&off);
+ timersub(&base->event_tv, &tv, &off);
+ timeout_correct(base, &off);
}
- event_tv = tv;
+ base->event_tv = tv;
- if (!(flags & EVLOOP_NONBLOCK))
- timeout_next(&tv);
+ if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK))
+ timeout_next(base, &tv);
else
timerclear(&tv);
/* If we have no events, we just exit */
- if (!event_haveevents())
+ if (!event_haveevents(base)) {
+ event_debug(("%s: no events registered.", __func__));
return (1);
+ }
- res = evsel->dispatch(evbase, &tv);
+ res = evsel->dispatch(base, evbase, &tv);
if (res == -1)
return (-1);
- timeout_process();
+ timeout_process(base);
- if (TAILQ_FIRST(&activequeue)) {
- event_process_active();
- if (flags & EVLOOP_ONCE)
+ if (base->event_count_active) {
+ event_process_active(base);
+ if (!base->event_count_active && (flags & EVLOOP_ONCE))
done = 1;
} else if (flags & EVLOOP_NONBLOCK)
done = 1;
- if (evsel->recalc(evbase, 0) == -1)
+ if (evsel->recalc(base, evbase, 0) == -1)
return (-1);
}
+ event_debug(("%s: asked to terminate loop.", __func__));
return (0);
}
@@ -337,15 +422,15 @@ event_once(int fd, short events,
if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
return (-1);
+ eonce->cb = callback;
+ eonce->arg = arg;
+
if (events == EV_TIMEOUT) {
if (tv == NULL) {
timerclear(&etv);
tv = &etv;
}
- eonce->cb = callback;
- eonce->arg = arg;
-
evtimer_set(&eonce->ev, event_once_cb, eonce);
} else if (events & (EV_READ|EV_WRITE)) {
events &= EV_READ|EV_WRITE;
@@ -365,18 +450,50 @@ void
event_set(struct event *ev, int fd, short events,
void (*callback)(int, short, void *), void *arg)
{
+ /* Take the current base - caller needs to set the real base later */
+ ev->ev_base = current_base;
+
ev->ev_callback = callback;
ev->ev_arg = arg;
-#ifdef WIN32
- ev->ev_fd = (HANDLE)fd;
- ev->overlap.hEvent = ev;
-#else
ev->ev_fd = fd;
-#endif
ev->ev_events = events;
ev->ev_flags = EVLIST_INIT;
ev->ev_ncalls = 0;
ev->ev_pncalls = NULL;
+
+ /* by default, we put new events into the middle priority */
+ ev->ev_pri = current_base->nactivequeues/2;
+}
+
+int
+event_base_set(struct event_base *base, struct event *ev)
+{
+ /* Only innocent events may be assigned to a different base */
+ if (ev->ev_flags != EVLIST_INIT)
+ return (-1);
+
+ ev->ev_base = base;
+ ev->ev_pri = current_base->nactivequeues/2;
+
+ return (0);
+}
+
+/*
+ * Set's the priority of an event - if an event is already scheduled
+ * changing the priority is going to fail.
+ */
+
+int
+event_priority_set(struct event *ev, int pri)
+{
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ return (-1);
+ if (pri < 0 || pri >= ev->ev_base->nactivequeues)
+ return (-1);
+
+ ev->ev_pri = pri;
+
+ return (0);
}
/*
@@ -409,7 +526,11 @@ event_pending(struct event *ev, short event, struct timeval *tv)
int
event_add(struct event *ev, struct timeval *tv)
{
- LOG_DBG((LOG_MISC, 55,
+ struct event_base *base = ev->ev_base;
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+
+ event_debug((
"event_add: event: %p, %s%s%scall %p",
ev,
ev->ev_events & EV_READ ? "EV_READ " : " ",
@@ -423,7 +544,7 @@ event_add(struct event *ev, struct timeval *tv)
struct timeval now;
if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
/* Check if it is active due to a timeout. Rescheduling
* this timeout before the callback can be executed
@@ -438,27 +559,27 @@ event_add(struct event *ev, struct timeval *tv)
*ev->ev_pncalls = 0;
}
- event_queue_remove(ev, EVLIST_ACTIVE);
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
}
gettimeofday(&now, NULL);
timeradd(&now, tv, &ev->ev_timeout);
- LOG_DBG((LOG_MISC, 55,
+ event_debug((
"event_add: timeout in %d seconds, call %p",
tv->tv_sec, ev->ev_callback));
- event_queue_insert(ev, EVLIST_TIMEOUT);
+ event_queue_insert(base, ev, EVLIST_TIMEOUT);
}
if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
- event_queue_insert(ev, EVLIST_INSERTED);
+ event_queue_insert(base, ev, EVLIST_INSERTED);
return (evsel->add(evbase, ev));
} else if ((ev->ev_events & EV_SIGNAL) &&
!(ev->ev_flags & EVLIST_SIGNAL)) {
- event_queue_insert(ev, EVLIST_SIGNAL);
+ event_queue_insert(base, ev, EVLIST_SIGNAL);
return (evsel->add(evbase, ev));
}
@@ -469,9 +590,21 @@ event_add(struct event *ev, struct timeval *tv)
int
event_del(struct event *ev)
{
- LOG_DBG((LOG_MISC, 80, "event_del: %p, callback %p",
+ struct event_base *base;
+ const struct eventop *evsel;
+ void *evbase;
+
+ event_debug(("event_del: %p, callback %p",
ev, ev->ev_callback));
+ /* An event without a base has not been added */
+ if (ev->ev_base == NULL)
+ return (-1);
+
+ base = ev->ev_base;
+ evsel = base->evsel;
+ evbase = base->evbase;
+
assert(!(ev->ev_flags & ~EVLIST_ALL));
/* See if we are just active executing this event in a loop */
@@ -481,16 +614,16 @@ event_del(struct event *ev)
}
if (ev->ev_flags & EVLIST_TIMEOUT)
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
if (ev->ev_flags & EVLIST_ACTIVE)
- event_queue_remove(ev, EVLIST_ACTIVE);
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
if (ev->ev_flags & EVLIST_INSERTED) {
- event_queue_remove(ev, EVLIST_INSERTED);
+ event_queue_remove(base, ev, EVLIST_INSERTED);
return (evsel->del(evbase, ev));
} else if (ev->ev_flags & EVLIST_SIGNAL) {
- event_queue_remove(ev, EVLIST_SIGNAL);
+ event_queue_remove(base, ev, EVLIST_SIGNAL);
return (evsel->del(evbase, ev));
}
@@ -509,18 +642,18 @@ event_active(struct event *ev, int res, short ncalls)
ev->ev_res = res;
ev->ev_ncalls = ncalls;
ev->ev_pncalls = NULL;
- event_queue_insert(ev, EVLIST_ACTIVE);
+ event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
}
int
-timeout_next(struct timeval *tv)
+timeout_next(struct event_base *base, struct timeval *tv)
{
struct timeval dflt = TIMEOUT_DEFAULT;
struct timeval now;
struct event *ev;
- if ((ev = RB_MIN(event_tree, &timetree)) == NULL) {
+ if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
*tv = dflt;
return (0);
}
@@ -538,96 +671,143 @@ timeout_next(struct timeval *tv)
assert(tv->tv_sec >= 0);
assert(tv->tv_usec >= 0);
- LOG_DBG((LOG_MISC, 60, "timeout_next: in %d seconds", tv->tv_sec));
+ event_debug(("timeout_next: in %d seconds", tv->tv_sec));
return (0);
}
-void
-timeout_correct(struct timeval *off)
+static void
+timeout_correct(struct event_base *base, struct timeval *off)
{
struct event *ev;
- /* We can modify the key element of the node without destroying
+ /*
+ * We can modify the key element of the node without destroying
* the key, beause we apply it to all in the right order.
*/
- RB_FOREACH(ev, event_tree, &timetree)
+ RB_FOREACH(ev, event_tree, &base->timetree)
timersub(&ev->ev_timeout, off, &ev->ev_timeout);
}
void
-timeout_process(void)
+timeout_process(struct event_base *base)
{
struct timeval now;
struct event *ev, *next;
gettimeofday(&now, NULL);
- for (ev = RB_MIN(event_tree, &timetree); ev; ev = next) {
+ for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
if (timercmp(&ev->ev_timeout, &now, >))
break;
- next = RB_NEXT(event_tree, &timetree, ev);
+ next = RB_NEXT(event_tree, &base->timetree, ev);
- event_queue_remove(ev, EVLIST_TIMEOUT);
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
/* delete this event from the I/O queues */
event_del(ev);
- LOG_DBG((LOG_MISC, 60, "timeout_process: call %p",
+ event_debug(("timeout_process: call %p",
ev->ev_callback));
event_active(ev, EV_TIMEOUT, 1);
}
}
void
-event_queue_remove(struct event *ev, int queue)
+event_queue_remove(struct event_base *base, struct event *ev, int queue)
{
+ int docount = 1;
+
if (!(ev->ev_flags & queue))
- errx(1, "%s: %p(fd %d) not on queue %x", __func__,
- ev, ev->ev_fd, queue);
+ event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+
+ if (ev->ev_flags & EVLIST_INTERNAL)
+ docount = 0;
+
+ if (docount)
+ base->event_count--;
ev->ev_flags &= ~queue;
switch (queue) {
case EVLIST_ACTIVE:
- TAILQ_REMOVE(&activequeue, ev, ev_active_next);
+ if (docount)
+ base->event_count_active--;
+ TAILQ_REMOVE(base->activequeues[ev->ev_pri],
+ ev, ev_active_next);
break;
case EVLIST_SIGNAL:
TAILQ_REMOVE(&signalqueue, ev, ev_signal_next);
break;
case EVLIST_TIMEOUT:
- RB_REMOVE(event_tree, &timetree, ev);
+ RB_REMOVE(event_tree, &base->timetree, ev);
break;
case EVLIST_INSERTED:
- TAILQ_REMOVE(&eventqueue, ev, ev_next);
+ TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
break;
default:
- errx(1, "%s: unknown queue %x", __func__, queue);
+ event_errx(1, "%s: unknown queue %x", __func__, queue);
}
}
void
-event_queue_insert(struct event *ev, int queue)
+event_queue_insert(struct event_base *base, struct event *ev, int queue)
{
- if (ev->ev_flags & queue)
- errx(1, "%s: %p(fd %d) already on queue %x", __func__,
- ev, ev->ev_fd, queue);
+ int docount = 1;
+
+ if (ev->ev_flags & queue) {
+ /* Double insertion is possible for active events */
+ if (queue & EVLIST_ACTIVE)
+ return;
+
+ event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+ }
+
+ if (ev->ev_flags & EVLIST_INTERNAL)
+ docount = 0;
+
+ if (docount)
+ base->event_count++;
ev->ev_flags |= queue;
switch (queue) {
case EVLIST_ACTIVE:
- TAILQ_INSERT_TAIL(&activequeue, ev, ev_active_next);
+ if (docount)
+ base->event_count_active++;
+ TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
+ ev,ev_active_next);
break;
case EVLIST_SIGNAL:
TAILQ_INSERT_TAIL(&signalqueue, ev, ev_signal_next);
break;
case EVLIST_TIMEOUT: {
- struct event *tmp = RB_INSERT(event_tree, &timetree, ev);
+ struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev);
assert(tmp == NULL);
break;
}
case EVLIST_INSERTED:
- TAILQ_INSERT_TAIL(&eventqueue, ev, ev_next);
+ TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
break;
default:
- errx(1, "%s: unknown queue %x", __func__, queue);
+ event_errx(1, "%s: unknown queue %x", __func__, queue);
}
}
+
+/* Functions for debugging */
+
+const char *
+event_get_version(void)
+{
+ return (LIBEVENT_VERSION);
+}
+
+/*
+ * No thread-safe interface needed - the information should be the same
+ * for all threads.
+ */
+
+const char *
+event_get_method(void)
+{
+ return (current_base->evsel->name);
+}
diff --git a/lib/libevent/event.h b/lib/libevent/event.h
index 70f04b7eb6b..5b2385a12c7 100644
--- a/lib/libevent/event.h
+++ b/lib/libevent/event.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: event.h,v 1.8 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: event.h,v 1.9 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
@@ -34,17 +34,23 @@ extern "C" {
#endif
#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+typedef unsigned char u_char;
#endif
+#define LIBEVENT_VERSION "1.0c"
+
#define EVLIST_TIMEOUT 0x01
#define EVLIST_INSERTED 0x02
#define EVLIST_SIGNAL 0x04
#define EVLIST_ACTIVE 0x08
+#define EVLIST_INTERNAL 0x10
#define EVLIST_INIT 0x80
/* EVLIST_X_ Private space: 0x1000-0xf000 */
-#define EVLIST_ALL (0xf000 | 0x8f)
+#define EVLIST_ALL (0xf000 | 0x9f)
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
@@ -72,24 +78,23 @@ struct { \
}
#endif /* !RB_ENTRY */
+struct event_base;
struct event {
TAILQ_ENTRY (event) ev_next;
TAILQ_ENTRY (event) ev_active_next;
TAILQ_ENTRY (event) ev_signal_next;
RB_ENTRY (event) ev_timeout_node;
-#ifdef WIN32
- HANDLE ev_fd;
- OVERLAPPED overlap;
-#else
+ struct event_base *ev_base;
int ev_fd;
-#endif
short ev_events;
short ev_ncalls;
short *ev_pncalls; /* Allows deletes in callback */
struct timeval ev_timeout;
+ int ev_pri; /* smaller numbers are higher priority */
+
void (*ev_callback)(int, short, void *arg);
void *ev_arg;
@@ -116,23 +121,32 @@ struct eventop {
void *(*init)(void);
int (*add)(void *, struct event *);
int (*del)(void *, struct event *);
- int (*recalc)(void *, int);
- int (*dispatch)(void *, struct timeval *);
+ int (*recalc)(struct event_base *, void *, int);
+ int (*dispatch)(struct event_base *, void *, struct timeval *);
};
#define TIMEOUT_DEFAULT {5, 0}
-void event_init(void);
+void *event_init(void);
int event_dispatch(void);
+int event_base_dispatch(struct event_base *);
+
+#define _EVENT_LOG_DEBUG 0
+#define _EVENT_LOG_MSG 1
+#define _EVENT_LOG_WARN 2
+#define _EVENT_LOG_ERR 3
+typedef void (*event_log_cb)(int severity, const char *msg);
+void event_set_log_callback(event_log_cb cb);
+
+/* Associate a different event base with an event */
+int event_base_set(struct event_base *, struct event *);
#define EVLOOP_ONCE 0x01
#define EVLOOP_NONBLOCK 0x02
int event_loop(int);
+int event_base_loop(struct event_base *, int);
int event_loopexit(struct timeval *); /* Causes the loop to exit */
-
-int timeout_next(struct timeval *);
-void timeout_correct(struct timeval *);
-void timeout_process(void);
+int event_base_loopexit(struct event_base *, struct timeval *);
#define evtimer_add(ev, tv) event_add(ev, tv)
#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
@@ -162,11 +176,23 @@ int event_pending(struct event *, short, struct timeval *);
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
#endif
+/* Some simple debugging functions */
+const char *event_get_version(void);
+const char *event_get_method(void);
+
+/* These functions deal with event priorities */
+
+int event_priority_init(int);
+int event_base_priority_init(struct event_base *, int);
+int event_priority_set(struct event *, int);
+
/* These functions deal with buffering input and output */
struct evbuffer {
u_char *buffer;
+ u_char *orig_buffer;
+ size_t misalign;
size_t totallen;
size_t off;
@@ -213,6 +239,7 @@ struct bufferevent {
struct bufferevent *bufferevent_new(int fd,
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+int bufferevent_priority_set(struct bufferevent *bufev, int pri);
void bufferevent_free(struct bufferevent *bufev);
int bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
@@ -229,7 +256,9 @@ void bufferevent_settimeout(struct bufferevent *bufev,
struct evbuffer *evbuffer_new(void);
void evbuffer_free(struct evbuffer *);
-int evbuffer_add(struct evbuffer *, u_char *, size_t);
+int evbuffer_expand(struct evbuffer *, size_t);
+int evbuffer_add(struct evbuffer *, void *, size_t);
+int evbuffer_remove(struct evbuffer *, void *, size_t);
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
int evbuffer_add_printf(struct evbuffer *, char *fmt, ...);
void evbuffer_drain(struct evbuffer *, size_t);
diff --git a/lib/libevent/kqueue.c b/lib/libevent/kqueue.c
index 78309cd6e8d..6280399efe4 100644
--- a/lib/libevent/kqueue.c
+++ b/lib/libevent/kqueue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kqueue.c,v 1.14 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: kqueue.c,v 1.15 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
@@ -44,29 +44,18 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <err.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
-#ifdef USE_LOG
-#include "log.h"
-#else
-#define LOG_DBG(x)
-#define log_error warn
-#endif
-
-#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__)
+#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
#define INTPTR(x) (intptr_t)x
#else
#define INTPTR(x) x
#endif
#include "event.h"
-
-extern struct event_list timequeue;
-extern struct event_list eventqueue;
-extern struct event_list addqueue;
+#include "log.h"
#define EVLIST_X_KQINKERNEL 0x1000
@@ -78,13 +67,13 @@ struct kqop {
struct kevent *events;
int nevents;
int kq;
-} kqueueop;
+};
void *kq_init (void);
int kq_add (void *, struct event *);
int kq_del (void *, struct event *);
-int kq_recalc (void *, int);
-int kq_dispatch (void *, struct timeval *);
+int kq_recalc (struct event_base *, void *, int);
+int kq_dispatch (struct event_base *, void *, struct timeval *);
int kq_insert (struct kqop *, struct kevent *);
const struct eventop kqops = {
@@ -100,38 +89,44 @@ void *
kq_init(void)
{
int kq;
+ struct kqop *kqueueop;
/* Disable kqueue when this environment variable is set */
if (!issetugid() && getenv("EVENT_NOKQUEUE"))
return (NULL);
- memset(&kqueueop, 0, sizeof(kqueueop));
+ if (!(kqueueop = calloc(1, sizeof(struct kqop))))
+ return (NULL);
/* Initalize the kernel queue */
if ((kq = kqueue()) == -1) {
- log_error("kqueue");
+ event_warn("kqueue");
+ free (kqueueop);
return (NULL);
}
- kqueueop.kq = kq;
+ kqueueop->kq = kq;
/* Initalize fields */
- kqueueop.changes = malloc(NEVENT * sizeof(struct kevent));
- if (kqueueop.changes == NULL)
+ kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
+ if (kqueueop->changes == NULL) {
+ free (kqueueop);
return (NULL);
- kqueueop.events = malloc(NEVENT * sizeof(struct kevent));
- if (kqueueop.events == NULL) {
- free (kqueueop.changes);
+ }
+ kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
+ if (kqueueop->events == NULL) {
+ free (kqueueop->changes);
+ free (kqueueop);
return (NULL);
}
- kqueueop.nevents = NEVENT;
+ kqueueop->nevents = NEVENT;
- return (&kqueueop);
+ return (kqueueop);
}
int
-kq_recalc(void *arg, int max)
+kq_recalc(struct event_base *base, void *arg, int max)
{
return (0);
}
@@ -150,7 +145,7 @@ kq_insert(struct kqop *kqop, struct kevent *kev)
newchange = realloc(kqop->changes,
nevents * sizeof(struct kevent));
if (newchange == NULL) {
- log_error("%s: malloc", __func__);
+ event_warn("%s: malloc", __func__);
return (-1);
}
kqop->changes = newchange;
@@ -163,7 +158,7 @@ kq_insert(struct kqop *kqop, struct kevent *kev)
* the next realloc will pick it up.
*/
if (newresult == NULL) {
- log_error("%s: malloc", __func__);
+ event_warn("%s: malloc", __func__);
return (-1);
}
kqop->events = newresult;
@@ -173,7 +168,7 @@ kq_insert(struct kqop *kqop, struct kevent *kev)
memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
- LOG_DBG((LOG_MISC, 70, "%s: fd %d %s%s",
+ event_debug(("%s: fd %d %s%s",
__func__, kev->ident,
kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
kev->flags == EV_DELETE ? " (del)" : ""));
@@ -188,7 +183,7 @@ kq_sighandler(int sig)
}
int
-kq_dispatch(void *arg, struct timeval *tv)
+kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
struct kqop *kqop = arg;
struct kevent *changes = kqop->changes;
@@ -204,14 +199,14 @@ kq_dispatch(void *arg, struct timeval *tv)
kqop->nchanges = 0;
if (res == -1) {
if (errno != EINTR) {
- log_error("kevent");
+ event_warn("kevent");
return (-1);
}
return (0);
}
- LOG_DBG((LOG_MISC, 80, "%s: kevent reports %d", __func__, res));
+ event_debug(("%s: kevent reports %d", __func__, res));
for (i = 0; i < res; i++) {
int which = 0;
diff --git a/lib/libevent/log.c b/lib/libevent/log.c
new file mode 100644
index 00000000000..6038b389199
--- /dev/null
+++ b/lib/libevent/log.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: log.c,v 1.3 2005/04/22 00:56:25 brad Exp $ */
+
+/*
+ * log.c
+ *
+ * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
+ *
+ * Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net>
+ *
+ * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ *
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include "misc.h"
+#endif
+#include <sys/types.h>
+#include <sys/tree.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_time.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "event.h"
+
+#include "log.h"
+
+static void _warn_helper(int severity, int log_errno, const char *fmt,
+ va_list ap);
+static void event_log(int severity, const char *msg);
+
+static int
+event_vsnprintf(char *str, size_t size, const char *format, va_list args)
+{
+ int r;
+ if (size == 0)
+ return -1;
+#ifdef WIN32
+ r = _vsnprintf(str, size, format, args);
+#else
+ r = vsnprintf(str, size, format, args);
+#endif
+ str[size-1] = '\0';
+ if (r < 0 || ((size_t)r) >= size) {
+ /* different platforms behave differently on overflow;
+ * handle both kinds. */
+ return -1;
+ }
+ return r;
+}
+
+void
+event_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_ERR, errno, fmt, ap);
+ va_end(ap);
+ exit(eval);
+}
+
+void
+event_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_WARN, errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_ERR, -1, fmt, ap);
+ va_end(ap);
+ exit(eval);
+}
+
+void
+event_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_WARN, -1, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_msgx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_MSG, -1, fmt, ap);
+ va_end(ap);
+}
+
+void
+_event_debugx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap);
+ va_end(ap);
+}
+
+static void
+_warn_helper(int severity, int log_errno, const char *fmt, va_list ap)
+{
+ char buf[1024];
+ size_t len;
+
+ if (fmt != NULL)
+ event_vsnprintf(buf, sizeof(buf), fmt, ap);
+ else
+ buf[0] = '\0';
+
+ if (log_errno >= 0) {
+ len = strlen(buf);
+ if (len < sizeof(buf) - 3) {
+ snprintf(buf + len, sizeof(buf) - len, ": %s",
+ strerror(log_errno));
+ }
+ }
+
+ event_log(severity, buf);
+}
+
+static event_log_cb log_fn = NULL;
+
+void
+event_set_log_callback(event_log_cb cb)
+{
+ log_fn = cb;
+}
+
+static void
+event_log(int severity, const char *msg)
+{
+ if (log_fn)
+ log_fn(severity, msg);
+ else {
+ const char *severity_str;
+ switch (severity) {
+ case _EVENT_LOG_DEBUG:
+ severity_str = "debug";
+ break;
+ case _EVENT_LOG_MSG:
+ severity_str = "msg";
+ break;
+ case _EVENT_LOG_WARN:
+ severity_str = "warn";
+ break;
+ case _EVENT_LOG_ERR:
+ severity_str = "err";
+ break;
+ default:
+ severity_str = "???";
+ break;
+ }
+ (void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
+ }
+}
diff --git a/lib/libevent/log.h b/lib/libevent/log.h
new file mode 100644
index 00000000000..614018d546c
--- /dev/null
+++ b/lib/libevent/log.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: log.h,v 1.3 2005/04/22 00:56:25 brad Exp $ */
+
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _LOG_H_
+#define _LOG_H_
+
+void event_err(int eval, const char *fmt, ...);
+void event_warn(const char *fmt, ...);
+void event_errx(int eval, const char *fmt, ...);
+void event_warnx(const char *fmt, ...);
+void event_msgx(const char *fmt, ...);
+void _event_debugx(const char *fmt, ...);
+#undef USE_DEBUG
+#ifdef USE_DEBUG
+#define event_debug(x) _event_debugx x
+#else
+#define event_debug(x)
+#endif
+
+#endif
diff --git a/lib/libevent/poll.c b/lib/libevent/poll.c
index d1f7e1628b9..bc3a19006a6 100644
--- a/lib/libevent/poll.c
+++ b/lib/libevent/poll.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: poll.c,v 1.5 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: poll.c,v 1.6 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
@@ -37,6 +37,7 @@
#include <sys/_time.h>
#endif
#include <sys/queue.h>
+#include <sys/tree.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
@@ -44,19 +45,11 @@
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <err.h>
-
-#ifdef USE_LOG
-#include "log.h"
-#else
-#define LOG_DBG(x)
-#define log_error(x) perror(x)
-#endif
#include "event.h"
+#include "event-internal.h"
#include "evsignal.h"
-
-extern struct event_list eventqueue;
+#include "log.h"
extern volatile sig_atomic_t evsignal_caught;
@@ -65,13 +58,13 @@ struct pollop {
struct pollfd *event_set;
struct event **event_back;
sigset_t evsigmask;
-} pollop;
+};
void *poll_init (void);
int poll_add (void *, struct event *);
int poll_del (void *, struct event *);
-int poll_recalc (void *, int);
-int poll_dispatch (void *, struct timeval *);
+int poll_recalc (struct event_base *, void *, int);
+int poll_dispatch (struct event_base *, void *, struct timeval *);
struct eventop pollops = {
"poll",
@@ -85,15 +78,18 @@ struct eventop pollops = {
void *
poll_init(void)
{
+ struct pollop *pollop;
+
/* Disable kqueue when this environment variable is set */
if (!issetugid() && getenv("EVENT_NOPOLL"))
return (NULL);
- memset(&pollop, 0, sizeof(pollop));
+ if (!(pollop = calloc(1, sizeof(struct pollop))))
+ return (NULL);
- evsignal_init(&pollop.evsigmask);
+ evsignal_init(&pollop->evsigmask);
- return (&pollop);
+ return (pollop);
}
/*
@@ -102,7 +98,7 @@ poll_init(void)
*/
int
-poll_recalc(void *arg, int max)
+poll_recalc(struct event_base *base, void *arg, int max)
{
struct pollop *pop = arg;
@@ -110,7 +106,7 @@ poll_recalc(void *arg, int max)
}
int
-poll_dispatch(void *arg, struct timeval *tv)
+poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
int res, i, count, sec, nfds;
struct event *ev;
@@ -118,7 +114,7 @@ poll_dispatch(void *arg, struct timeval *tv)
count = pop->event_count;
nfds = 0;
- TAILQ_FOREACH(ev, &eventqueue, ev_next) {
+ TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
if (nfds + 1 >= count) {
if (count < 32)
count = 32;
@@ -129,13 +125,13 @@ poll_dispatch(void *arg, struct timeval *tv)
pop->event_set = realloc(pop->event_set,
count * sizeof(struct pollfd));
if (pop->event_set == NULL) {
- log_error("realloc");
+ event_warn("realloc");
return (-1);
}
pop->event_back = realloc(pop->event_back,
count * sizeof(struct event *));
if (pop->event_back == NULL) {
- log_error("realloc");
+ event_warn("realloc");
return (-1);
}
pop->event_count = count;
@@ -166,7 +162,7 @@ poll_dispatch(void *arg, struct timeval *tv)
if (evsignal_deliver(&pop->evsigmask) == -1)
return (-1);
- sec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
+ sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
res = poll(pop->event_set, nfds, sec);
if (evsignal_recalc(&pop->evsigmask) == -1)
@@ -174,7 +170,7 @@ poll_dispatch(void *arg, struct timeval *tv)
if (res == -1) {
if (errno != EINTR) {
- log_error("poll");
+ event_warn("poll");
return (-1);
}
@@ -183,7 +179,7 @@ poll_dispatch(void *arg, struct timeval *tv)
} else if (evsignal_caught)
evsignal_process();
- LOG_DBG((LOG_MISC, 80, "%s: poll reports %d", __func__, res));
+ event_debug(("%s: poll reports %d", __func__, res));
if (res == 0)
return (0);
diff --git a/lib/libevent/select.c b/lib/libevent/select.c
index fb692729d80..59e4f9a3393 100644
--- a/lib/libevent/select.c
+++ b/lib/libevent/select.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: select.c,v 1.8 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: select.c,v 1.9 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
@@ -37,25 +37,18 @@
#include <sys/_time.h>
#endif
#include <sys/queue.h>
+#include <sys/tree.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <err.h>
-
-#ifdef USE_LOG
-#include "log.h"
-#else
-#define LOG_DBG(x)
-#define log_error(x) perror(x)
-#endif
#include "event.h"
+#include "event-internal.h"
#include "evsignal.h"
-
-extern struct event_list eventqueue;
+#include "log.h"
#ifndef howmany
#define howmany(x, y) (((x)+((y)-1))/(y))
@@ -69,13 +62,13 @@ struct selectop {
fd_set *event_readset;
fd_set *event_writeset;
sigset_t evsigmask;
-} sop;
+};
void *select_init (void);
int select_add (void *, struct event *);
int select_del (void *, struct event *);
-int select_recalc (void *, int);
-int select_dispatch (void *, struct timeval *);
+int select_recalc (struct event_base *, void *, int);
+int select_dispatch (struct event_base *, void *, struct timeval *);
const struct eventop selectops = {
"select",
@@ -89,15 +82,18 @@ const struct eventop selectops = {
void *
select_init(void)
{
+ struct selectop *sop;
+
/* Disable kqueue when this environment variable is set */
if (!issetugid() && getenv("EVENT_NOSELECT"))
return (NULL);
- memset(&sop, 0, sizeof(sop));
+ if (!(sop = calloc(1, sizeof(struct selectop))))
+ return (NULL);
- evsignal_init(&sop.evsigmask);
+ evsignal_init(&sop->evsigmask);
- return (&sop);
+ return (sop);
}
/*
@@ -106,7 +102,7 @@ select_init(void)
*/
int
-select_recalc(void *arg, int max)
+select_recalc(struct event_base *base, void *arg, int max)
{
struct selectop *sop = arg;
fd_set *readset, *writeset;
@@ -117,7 +113,7 @@ select_recalc(void *arg, int max)
sop->event_fds = max;
if (!sop->event_fds) {
- TAILQ_FOREACH(ev, &eventqueue, ev_next)
+ TAILQ_FOREACH(ev, &base->eventqueue, ev_next)
if (ev->ev_fd > sop->event_fds)
sop->event_fds = ev->ev_fd;
}
@@ -125,12 +121,12 @@ select_recalc(void *arg, int max)
fdsz = howmany(sop->event_fds + 1, NFDBITS) * sizeof(fd_mask);
if (fdsz > sop->event_fdsz) {
if ((readset = realloc(sop->event_readset, fdsz)) == NULL) {
- log_error("malloc");
+ event_warn("malloc");
return (-1);
}
if ((writeset = realloc(sop->event_writeset, fdsz)) == NULL) {
- log_error("malloc");
+ event_warn("malloc");
free(readset);
return (-1);
}
@@ -149,7 +145,7 @@ select_recalc(void *arg, int max)
}
int
-select_dispatch(void *arg, struct timeval *tv)
+select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
{
int maxfd, res;
struct event *ev, *next;
@@ -158,7 +154,7 @@ select_dispatch(void *arg, struct timeval *tv)
memset(sop->event_readset, 0, sop->event_fdsz);
memset(sop->event_writeset, 0, sop->event_fdsz);
- TAILQ_FOREACH(ev, &eventqueue, ev_next) {
+ 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)
@@ -176,7 +172,7 @@ select_dispatch(void *arg, struct timeval *tv)
if (res == -1) {
if (errno != EINTR) {
- log_error("select");
+ event_warn("select");
return (-1);
}
@@ -185,10 +181,10 @@ select_dispatch(void *arg, struct timeval *tv)
} else if (evsignal_caught)
evsignal_process();
- LOG_DBG((LOG_MISC, 80, "%s: select reports %d", __func__, res));
+ event_debug(("%s: select reports %d", __func__, res));
maxfd = 0;
- for (ev = TAILQ_FIRST(&eventqueue); ev != NULL; ev = next) {
+ for (ev = TAILQ_FIRST(&base->eventqueue); ev != NULL; ev = next) {
next = TAILQ_NEXT(ev, ev_next);
res = 0;
@@ -201,6 +197,8 @@ select_dispatch(void *arg, struct timeval *tv)
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;
diff --git a/lib/libevent/signal.c b/lib/libevent/signal.c
index 2bd98148760..8df05c5d32a 100644
--- a/lib/libevent/signal.c
+++ b/lib/libevent/signal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: signal.c,v 1.5 2005/04/19 08:07:45 deraadt Exp $ */
+/* $OpenBSD: signal.c,v 1.6 2005/04/22 00:56:25 brad Exp $ */
/*
* Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
@@ -37,23 +37,20 @@
#include <sys/_time.h>
#endif
#include <sys/queue.h>
+#include <sys/socket.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
-#include <err.h>
-
-#ifdef USE_LOG
-#include "log.h"
-#else
-#define LOG_DBG(x)
-#define log_error(x) perror(x)
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
#endif
#include "event.h"
#include "evsignal.h"
+#include "log.h"
extern struct event_list signalqueue;
@@ -61,26 +58,63 @@ static short evsigcaught[NSIG];
static int needrecalc;
volatile sig_atomic_t evsignal_caught = 0;
-void evsignal_process(void);
-int evsignal_recalc(sigset_t *);
-int evsignal_deliver(sigset_t *);
+static struct event ev_signal;
+static int ev_signal_pair[2];
+static int ev_signal_added;
+
+/* Callback for when the signal handler write a byte to our signaling socket */
+static void evsignal_cb(int fd, short what, void *arg)
+{
+ static char signals[100];
+ struct event *ev = arg;
+ int n;
+
+ n = read(fd, signals, sizeof(signals));
+ if (n == -1)
+ event_err(1, "%s: read", __func__);
+ event_add(ev, NULL);
+}
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+ if (fcntl(x, F_SETFD, 1) == -1) \
+ event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
void
evsignal_init(sigset_t *evsigmask)
{
sigemptyset(evsigmask);
+
+ /*
+ * Our signal handler is going to write to one end of the socket
+ * pair to wake up our event loop. The event loop then scans for
+ * signals that got delivered.
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
+ event_err(1, "%s: socketpair", __func__);
+
+ FD_CLOSEONEXEC(ev_signal_pair[0]);
+ FD_CLOSEONEXEC(ev_signal_pair[1]);
+
+ event_set(&ev_signal, ev_signal_pair[1], EV_READ,
+ evsignal_cb, &ev_signal);
+ ev_signal.ev_flags |= EVLIST_INTERNAL;
}
int
evsignal_add(sigset_t *evsigmask, struct event *ev)
{
int evsignal;
-
+
if (ev->ev_events & (EV_READ|EV_WRITE))
- errx(1, "%s: EV_SIGNAL incompatible use", __func__);
+ event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
evsignal = EVENT_SIGNAL(ev);
sigaddset(evsigmask, evsignal);
-
+
return (0);
}
@@ -105,6 +139,9 @@ evsignal_handler(int sig)
{
evsigcaught[sig]++;
evsignal_caught = 1;
+
+ /* Wake up our notification mechanism */
+ write(ev_signal_pair[0], "a", 1);
}
int
@@ -113,19 +150,24 @@ evsignal_recalc(sigset_t *evsigmask)
struct sigaction sa;
struct event *ev;
+ if (!ev_signal_added) {
+ ev_signal_added = 1;
+ event_add(&ev_signal, NULL);
+ }
+
if (TAILQ_FIRST(&signalqueue) == NULL && !needrecalc)
return (0);
needrecalc = 0;
if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1)
return (-1);
-
+
/* Reinstall our signal handler. */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = evsignal_handler;
sa.sa_mask = *evsigmask;
sa.sa_flags |= SA_RESTART;
-
+
TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
return (-1);