[Dovecot] [PATCH] Request for testing: BSD kqueue ioloop handler

Andrey Panin pazke at donpac.ru
Mon Oct 25 15:58:44 EEST 2004


Hello,

attached patch adds experimental ioloop handler which uses BSD kqueue API.
It compiles and survives my small test program, but not thoroughly
tested because I have no suitable BSD machine to torture.

Brave owners of (Free|Net|Open)BSD please test and report results :)

Best regards.

-- 
Andrey Panin		| Linux and UNIX system administrator
pazke at donpac.ru		| PGP key: wwwkeys.pgp.net
-------------- next part --------------
diff -urpNX /usr/share/dontdiff dovecot-1.0-test51.vanilla/configure.in dovecot-1.0-test51/configure.in
--- dovecot-1.0-test51.vanilla/configure.in	2004-10-21 06:37:24.000000000 +0400
+++ dovecot-1.0-test51/configure.in	2004-10-25 14:06:44.000000000 +0400
@@ -269,6 +269,17 @@ if test "$ioloop" = "epoll"; then
   AC_CHECK_FUNC(epoll_create, [
     AC_DEFINE(IOLOOP_EPOLL,, Implement I/O loop with Linux 2.6 epoll())
     have_ioloop=yes
+    ioloop=epoll
+  ], [
+    ioloop=""
+  ])
+fi
+
+if test "$ioloop" = "" || test "$ioloop" = "kqueue"; then
+  AC_CHECK_FUNC(kqueue, [
+    AC_DEFINE(IOLOOP_KQUEUE,, Implement I/O loop with BSD kqueue)
+    have_ioloop=yes
+    ioloop=kqueue
   ], [
     ioloop=""
   ])
diff -urpNX /usr/share/dontdiff dovecot-1.0-test51.vanilla/src/lib/ioloop-kqueue.c dovecot-1.0-test51/src/lib/ioloop-kqueue.c
--- dovecot-1.0-test51.vanilla/src/lib/ioloop-kqueue.c	1970-01-01 03:00:00.000000000 +0300
+++ dovecot-1.0-test51/src/lib/ioloop-kqueue.c	2004-10-25 16:12:51.000000000 +0400
@@ -0,0 +1,201 @@
+/*
+ * BSD kqueue based ioloop handler.
+ *
+ * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published 
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* @UNSAFE: whole file */
+
+#include "lib.h"
+#include "iolist.h"
+#include "ioloop-internal.h"
+
+#ifdef IOLOOP_KQUEUE
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <unistd.h>
+	      
+#define INITIAL_KQUEUE_EVENTS	128
+
+struct ioloop_handler_data {
+	int kq;
+
+	unsigned int events_size, events_pos, events_changed;
+	struct kevent *events;
+
+	unsigned int idx_size;
+	struct io_list **fd_index;
+};
+
+void io_loop_handler_init(struct ioloop *ioloop)
+{
+	struct ioloop_handler_data *data;
+
+	ioloop->handler_data = data =
+		p_new(ioloop->pool, struct ioloop_handler_data, 1);
+
+	data->events_pos = 0;
+	data->events_changed = 0;
+	data->events_size = INITIAL_KQUEUE_EVENTS;
+	data->events = p_new(ioloop->pool, struct kevent, data->events_size);
+
+	data->idx_size = INITIAL_KQUEUE_EVENTS;
+	data->fd_index = p_new(ioloop->pool, struct io_list *, data->idx_size);
+
+	data->kq = kqueue();
+	if (data->kq < 0)
+		i_panic("kqueue(): %m");
+}
+
+void io_loop_handler_deinit(struct ioloop *ioloop)
+{
+	struct ioloop_handler_data *data = ioloop->handler_data;
+
+	close(data->kq);
+	p_free(ioloop->pool, data->events);
+	p_free(ioloop->pool, data->fd_index);
+	p_free(ioloop->pool, data);
+}
+
+void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+{
+	struct ioloop_handler_data *data = ioloop->handler_data;
+	struct io_list *list;
+	struct kevent *event;
+	unsigned int old_size;
+	int fd = io->fd;
+
+	list = data->fd_index[fd];
+	if (list == NULL) {
+		if ((unsigned int) fd >= data->idx_size) {
+                	/* grow the fd -> iolist array */
+			old_size = data->idx_size;
+
+			data->idx_size = nearest_power((unsigned int) fd+1);
+
+			i_assert(data->idx_size < (size_t)-1 / sizeof(int));
+
+			data->fd_index = p_realloc(ioloop->pool, data->fd_index,
+						   sizeof(int) * old_size,
+						   sizeof(int) * data->idx_size);
+		}
+
+		data->fd_index[fd] = list =
+			p_new(ioloop->pool, struct io_list, 1);
+	}
+
+	if (data->events_pos >= data->events_size) {
+		old_size = data->events_size;
+
+		data->events_size = nearest_power(data->events_size + 1);
+
+		i_assert(data->events_size < (size_t)-1 / sizeof(int));
+
+		data->events = p_realloc(ioloop->pool, data->events,
+					 sizeof(int) * old_size,
+					 sizeof(int) * data->events_size);
+	}
+	data->events_pos++;
+
+	iolist_add(list, io);
+
+	event = data->events + data->events_changed;
+	data->events_changed++;
+
+	EV_SET(event, fd, iolist_events(list, EVFILT_READ, EVFILT_WRITE),
+		EV_ADD | EV_EOF, 0, 0, io);
+}
+
+void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
+{
+	struct ioloop_handler_data *data = ioloop->handler_data;
+	struct io_list *list = data->fd_index[io->fd];
+	struct kevent *event;
+	int i, changed = data->events_changed;
+
+        iolist_del(list, io);
+
+	/* Check ios not yet added to the queue */
+	for (i = 0 ; i < changed ; i++) {
+		if (data->events[i].udata == io) {
+			if (i < changed - 1)
+				data->events[i] = data->events[changed];
+			data->events_changed--;
+			return;
+		}
+	}
+
+	event = data->events + data->events_changed;
+	data->events_changed++;
+
+	EV_SET(event, io->fd,
+		io->condition == IO_READ ? EVFILT_READ : EVFILT_WRITE,
+		EV_DELETE | EV_EOF, 0, 0, io);
+}
+
+void io_loop_handler_run(struct ioloop *ioloop)
+{
+	struct ioloop_handler_data *data = ioloop->handler_data;
+	struct io_list *list;
+	struct kevent *event;
+	struct io *io;
+	struct timespec ts;
+	struct timeval tv;
+	unsigned int t_id;
+	int ret, i, call;
+
+        /* get the time left for next timeout task */
+	io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
+	TIMEVAL_TO_TIMESPEC(&tv, &ts);
+
+	ret = kevent(data->kq, data->events, data->events_changed,
+		     data->events, data->events_size, &ts);
+
+	if (ret < 0 && errno != EINTR)
+		i_fatal("kevent(): %m");
+
+	data->events_changed = 0;
+
+	/* execute timeout handlers */
+        io_loop_handle_timeouts(ioloop);
+
+	if (ret <= 0 || !ioloop->running) {
+		/* No events */
+		return;
+	}
+
+	for (event = data->events ; ret-- > 0 ; event++) {
+		list = data->fd_index[(int)event->ident];
+
+		for (i = 0; i < IOLIST_IOS_PER_FD; i++) {
+			io = list->ios[i];
+			if (io == NULL)
+				continue;
+
+			call = FALSE;
+			if ((event->filter & EV_EOF) != 0) {
+				call = TRUE;
+			} else if ((io->condition & IO_READ) != 0) {
+				call = event->filter & EVFILT_READ;
+			} else if ((io->condition & IO_WRITE) != 0) {
+				call = event->filter & EVFILT_WRITE;
+			}
+
+			if (call) {
+				t_id = t_push();
+				io->callback(io->context);
+				if (t_pop() != t_id)
+					i_panic("Leaked a t_pop() call!");
+			}
+		}
+	}
+}
+
+#endif	/* IOLOOP_KQUEUE */
diff -urpNX /usr/share/dontdiff dovecot-1.0-test51.vanilla/src/lib/Makefile.am dovecot-1.0-test51/src/lib/Makefile.am
--- dovecot-1.0-test51.vanilla/src/lib/Makefile.am	2004-10-25 14:09:22.000000000 +0400
+++ dovecot-1.0-test51/src/lib/Makefile.am	2004-10-25 14:06:45.000000000 +0400
@@ -31,6 +31,7 @@ liblib_a_SOURCES = \
 	ioloop-poll.c \
 	ioloop-select.c \
 	ioloop-epoll.c \
+	ioloop-kqueue.c \
 	iolist.c \
 	lib.c \
 	lib-signals.c \
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://dovecot.org/pipermail/dovecot/attachments/20041025/ebf9d9a4/attachment-0001.bin>


More information about the dovecot mailing list