diff options
-rw-r--r-- | lib/libevent/buffer.c | 202 | ||||
-rw-r--r-- | lib/libevent/err.c | 97 | ||||
-rw-r--r-- | lib/libevent/evbuffer.c | 18 | ||||
-rw-r--r-- | lib/libevent/event-internal.h | 56 | ||||
-rw-r--r-- | lib/libevent/event.c | 408 | ||||
-rw-r--r-- | lib/libevent/event.h | 59 | ||||
-rw-r--r-- | lib/libevent/kqueue.c | 63 | ||||
-rw-r--r-- | lib/libevent/log.c | 208 | ||||
-rw-r--r-- | lib/libevent/log.h | 45 | ||||
-rw-r--r-- | lib/libevent/poll.c | 46 | ||||
-rw-r--r-- | lib/libevent/select.c | 50 | ||||
-rw-r--r-- | lib/libevent/signal.c | 74 |
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(¤t_base->event_tv, NULL); - RB_INIT(&timetree); - TAILQ_INIT(&eventqueue); - TAILQ_INIT(&activequeue); + RB_INIT(¤t_base->timetree); + TAILQ_INIT(¤t_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); |