From f266d1322c0c27aa6e047ed910bb65a20b03cc26 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 24 Mar 2008 22:56:18 -0400 Subject: [PATCH] Implement kqueue()/kevent() ioset backend. configure.in: Check for , kqueue() and kevent(). If kevent() is present, default to enabling ioset-kevent. src/Makefile.am: Include ioset-kevent.c as extra source. src/ioset-kevent.c: New file. src/ioset.c: Update name for this event backend. --- configure.in | 14 ++++- src/Makefile.am | 1 + src/ioset-kevent.c | 130 +++++++++++++++++++++++++++++++++++++++++++++ src/ioset.c | 8 +-- 4 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 src/ioset-kevent.c diff --git a/configure.in b/configure.in index 9a154d7..30be5ea 100644 --- a/configure.in +++ b/configure.in @@ -69,7 +69,7 @@ AC_HEADER_TIME AC_STRUCT_TM dnl Would rather not bail on headers, BSD has alot of the functions elsewhere. -Jedi -AC_CHECK_HEADERS(fcntl.h malloc.h netdb.h arpa/inet.h netinet/in.h sys/resource.h sys/timeb.h sys/times.h sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h unistd.h getopt.h memory.h regex.h arpa/inet.h sys/mman.h sys/stat.h dirent.h sys/epoll.h,,) +AC_CHECK_HEADERS(fcntl.h malloc.h netdb.h arpa/inet.h netinet/in.h sys/resource.h sys/timeb.h sys/times.h sys/param.h sys/socket.h sys/time.h sys/types.h sys/wait.h unistd.h getopt.h memory.h regex.h arpa/inet.h sys/mman.h sys/stat.h dirent.h sys/epoll.h sys/event.h,,) dnl portability stuff, hurray! -Jedi AC_CHECK_MEMBER([struct sockaddr.sa_len], @@ -83,7 +83,7 @@ AC_CHECK_MEMBER([struct addrinfo.ai_flags], #include ]) dnl We have fallbacks in case these are missing, so just check for them. -AC_CHECK_FUNCS(freeaddrinfo getaddrinfo gai_strerror getnameinfo getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit getopt getopt_long regcomp regexec regfree sysconf inet_aton epoll_create select gettimeofday times GetProcessTimes mprotect,,) +AC_CHECK_FUNCS(freeaddrinfo getaddrinfo gai_strerror getnameinfo getpagesize memcpy memset strdup strerror strsignal localtime_r setrlimit getopt getopt_long regcomp regexec regfree sysconf inet_aton epoll_create kqueue kevent select gettimeofday times GetProcessTimes mprotect,,) dnl Check for the fallbacks for functions missing above. if test $ac_cv_func_gettimeofday = no; then @@ -256,6 +256,16 @@ if test "x$withval" = xyes ; then IOMUXES="$IOMUXES epoll" fi +AC_ARG_WITH([kevent], +[ --without-kevent Disables the kevent() I/O backend], +[], +[withval="$ac_cv_func_kevent"]) +if test "x$withval" = xyes ; then + AC_DEFINE(WITH_IOSET_KEVENT, 1, [Define if using the kevent I/O backend]) + MODULE_OBJS="$MODULE_OBJS ioset-kevent.\$(OBJEXT)" + IOMUXES="$IOMUXES kevent" +fi + IOMUXES=`echo $IOMUXES | sed 's/^ +//'` if test "x$IOMUXES" = "x" ; then AC_MSG_ERROR([No supported I/O multiplexing backend found]) diff --git a/src/Makefile.am b/src/Makefile.am index 76b4ca3..53522ac 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,6 +39,7 @@ EXTRA_srvx_SOURCES = \ alloc-srvx.c \ config.h.win32 \ ioset-epoll.c \ + ioset-kqueue.c \ ioset-select.c \ ioset-win32.c \ mail-common.c \ diff --git a/src/ioset-kevent.c b/src/ioset-kevent.c new file mode 100644 index 0000000..02a8511 --- /dev/null +++ b/src/ioset-kevent.c @@ -0,0 +1,130 @@ +/* ioset kqueue()/kevent() backend for srvx + * Copyright 2008 srvx Development Team + * + * This file is part of srvx. + * + * srvx is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with srvx; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ioset-impl.h" +#include "common.h" +#include "log.h" + +#ifdef HAVE_SYS_EVENT_H +# include +#endif + +#define MAX_EVENTS 16 + +extern int clock_skew; +static int kq_fd; + +static int +ioset_kevent_init(void) +{ + kq_fd = kqueue(); + return kq_fd >= 0; +} + +static void +ioset_kevent_add(struct io_fd *fd) +{ + struct kevent changes[2]; + int nchanges = 0; + int res; + + EV_SET(&changes[nchanges++], fd->fd, EVFILT_READ, EV_ADD, 0, 0, fd); + if (fd_wants_writes(fd)) { + EV_SET(&changes[nchanges++], fd->fd, EVFILT_WRITE, EV_ADD, 0, 0, fd); + } + res = kevent(kq_fd, changes, nchanges, NULL, 0, NULL); + if (res < 0) { + log_module(MAIN_LOG, LOG_ERROR, "kevent() add failed: %s", strerror(errno)); + } +} + +static void +ioset_kevent_remove(struct io_fd *fd, int closed) +{ + if (!closed) { + struct kevent changes[2]; + int nchanges = 0; + int res; + + EV_SET(&changes[nchanges++], fd->fd, EVFILT_READ, EV_DELETE, 0, 0, fd); + EV_SET(&changes[nchanges++], fd->fd, EVFILT_WRITE, EV_DELETE, 0, 0, fd); + res = kevent(kq_fd, changes, nchanges, NULL, 0, NULL); + if (res < 0) { + log_module(MAIN_LOG, LOG_ERROR, "kevent() remove failed: %s", strerror(errno)); + } + } +} + +static void +ioset_kevent_update(struct io_fd *fd) +{ + ioset_kevent_add(fd); +} + +static void +ioset_kevent_cleanup(void) +{ + close(kq_fd); +} + +static int +ioset_kevent_loop(struct timeval *timeout) +{ + struct kevent events[MAX_EVENTS]; + struct timespec ts; + struct timespec *pts; + int is_write; + int is_read; + int res; + int ii; + + /* Try to get events from the kernel. */ + if (timeout) { + ts.tv_sec = timeout->tv_sec; + ts.tv_nsec = timeout->tv_usec * 1000; + pts = &ts; + } else { + pts = NULL; + } + res = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, pts); + if (res < 0) { + log_module(MAIN_LOG, LOG_ERROR, "kevent() poll failed: %s", strerror(errno)); + return 1; + } + + /* Process the events we got. */ + for (ii = 0; ii < res; ++ii) { + is_write = events[ii].filter == EVFILT_WRITE; + is_read = events[ii].filter == EVFILT_READ; + ioset_events(events[ii].udata, is_read, is_write); + } + + return 0; +} + +struct io_engine io_engine_kevent = { + .name = "kevent", + .init = ioset_kevent_init, + .add = ioset_kevent_add, + .remove = ioset_kevent_remove, + .update = ioset_kevent_update, + .loop = ioset_kevent_loop, + .cleanup = ioset_kevent_cleanup, +}; diff --git a/src/ioset.c b/src/ioset.c index 84bcf01..ced561f 100644 --- a/src/ioset.c +++ b/src/ioset.c @@ -134,7 +134,7 @@ ioq_grow(struct ioq *ioq) { return new_size - ioq->put; } -extern struct io_engine io_engine_kqueue; +extern struct io_engine io_engine_kevent; extern struct io_engine io_engine_epoll; extern struct io_engine io_engine_win32; extern struct io_engine io_engine_select; @@ -145,9 +145,9 @@ ioset_init(void) if (engine) /* someone beat us to it */ return; -#if WITH_IOSET_KQUEUE - if (!engine && io_engine_kqueue.init()) - engine = &io_engine_kqueue; +#if WITH_IOSET_KEVENT + if (!engine && io_engine_kevent.init()) + engine = &io_engine_kevent; #endif #if WITH_IOSET_EPOLL -- 2.20.1