Implement kqueue()/kevent() ioset backend.
authorMichael Poole <mdpoole@troilus.org>
Tue, 25 Mar 2008 02:56:18 +0000 (22:56 -0400)
committerMichael Poole <mdpoole@troilus.org>
Tue, 25 Mar 2008 02:56:18 +0000 (22:56 -0400)
configure.in: Check for <sys/event.h>, 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
src/Makefile.am
src/ioset-kevent.c [new file with mode: 0644]
src/ioset.c

index 9a154d7fc371d6bd6e249a7f14021e120ec349b6..30be5ea1f40f7d4282e04eb3dc01aa3cf34ff899 100644 (file)
@@ -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 <netdb.h>])
 
 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])
index 76b4ca3d1806b9a39d189f443976757899a883b2..53522acd87c5cb83715c8aca0fc64d842bd8980a 100644 (file)
@@ -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 (file)
index 0000000..02a8511
--- /dev/null
@@ -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 <sys/event.h>
+#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,
+};
index 84bcf01d20094eba5719bcb64892fb7b9043ce90..ced561f72622fc82509a5298a28aa987949c0ef6 100644 (file)
@@ -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