[dovecot-cvs] dovecot/src/lib Makefile.am, 1.62.2.1, 1.62.2.2 ioloop-epoll.c, 1.11.2.1, 1.11.2.2 ioloop-internal.h, 1.16, 1.16.2.1 ioloop-iolist.c, NONE, 1.1.2.1 ioloop-iolist.h, NONE, 1.1.2.1 ioloop-kqueue.c, 1.4.2.1, 1.4.2.2 ioloop-notify-kqueue.c, 1.3, 1.3.2.1 ioloop-poll.c, 1.32, 1.32.2.1

cras at dovecot.org cras at dovecot.org
Wed Aug 16 18:54:59 EEST 2006


Update of /var/lib/cvs/dovecot/src/lib
In directory talvi:/tmp/cvs-serv9264

Modified Files:
      Tag: branch_1_0
	Makefile.am ioloop-epoll.c ioloop-internal.h ioloop-kqueue.c 
	ioloop-notify-kqueue.c ioloop-poll.c 
Added Files:
      Tag: branch_1_0
	ioloop-iolist.c ioloop-iolist.h 
Log Message:
Rewrote much of the kqueue code. It didn't work correctly if there were both
input and output I/O handlers added for the same file descriptor. The code
works now very much like epoll code. Did also several cleanups.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.62.2.1
retrieving revision 1.62.2.2
diff -u -d -r1.62.2.1 -r1.62.2.2
--- Makefile.am	17 Jun 2006 16:24:54 -0000	1.62.2.1
+++ Makefile.am	16 Aug 2006 15:54:56 -0000	1.62.2.2
@@ -32,6 +32,7 @@
 	istream-mmap.c \
 	istream-seekable.c \
 	ioloop.c \
+	ioloop-iolist.c \
 	ioloop-notify-none.c \
 	ioloop-notify-dn.c \
 	ioloop-notify-inotify.c \
@@ -114,6 +115,7 @@
 	istream-internal.h \
 	istream-seekable.h \
 	ioloop.h \
+	ioloop-iolist.h \
 	ioloop-internal.h \
 	lib.h \
 	lib-signals.h \

Index: ioloop-epoll.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-epoll.c,v
retrieving revision 1.11.2.1
retrieving revision 1.11.2.2
diff -u -d -r1.11.2.1 -r1.11.2.2
--- ioloop-epoll.c	16 Jun 2006 10:38:27 -0000	1.11.2.1
+++ ioloop-epoll.c	16 Aug 2006 15:54:56 -0000	1.11.2.2
@@ -6,39 +6,23 @@
  * This software is released under the MIT license.
  */
 
-/* @UNSAFE: whole file */
-
 #include "lib.h"
 #include "array.h"
 #include "fd-close-on-exec.h"
 #include "ioloop-internal.h"
+#include "ioloop-iolist.h"
 
 #ifdef IOLOOP_EPOLL
 
 #include <sys/epoll.h>
 #include <unistd.h>
 
-#define INITIAL_EPOLL_EVENTS	128
-
-enum {
-	EPOLL_LIST_INPUT,
-	EPOLL_LIST_OUTPUT,
-	EPOLL_LIST_ERROR,
-
-	EPOLL_IOS_PER_FD
-};
-
 struct ioloop_handler_context {
 	int epfd;
-	int events_size, events_pos;
-	struct epoll_event *events;
 
-	unsigned int idx_size;
+	unsigned int deleted_count;
 	array_t ARRAY_DEFINE(fd_index, struct io_list *);
-};
-
-struct io_list {
-	struct io *ios[EPOLL_IOS_PER_FD];
+	array_t ARRAY_DEFINE(events, struct epoll_event);
 };
 
 void io_loop_handler_init(struct ioloop *ioloop)
@@ -48,16 +32,12 @@
 	ioloop->handler_context = ctx =
 		p_new(ioloop->pool, struct ioloop_handler_context, 1);
 
-	ctx->events_pos = 0;
-	ctx->events_size = INITIAL_EPOLL_EVENTS;
-	ctx->events = p_new(ioloop->pool, struct epoll_event,
-			    ctx->events_size);
-
-	ctx->idx_size = INITIAL_EPOLL_EVENTS;
+	ARRAY_CREATE(&ctx->events, ioloop->pool, struct epoll_event,
+		     IOLOOP_INITIAL_FD_COUNT);
 	ARRAY_CREATE(&ctx->fd_index, ioloop->pool,
-		     struct io_list *, ctx->idx_size);
+		     struct io_list *, IOLOOP_INITIAL_FD_COUNT);
 
-	ctx->epfd = epoll_create(INITIAL_EPOLL_EVENTS);
+	ctx->epfd = epoll_create(IOLOOP_INITIAL_FD_COUNT);
 	if (ctx->epfd < 0)
 		i_fatal("epoll_create(): %m");
 	fd_close_on_exec(ctx->epfd, TRUE);
@@ -70,7 +50,7 @@
 	if (close(ctx->epfd) < 0)
 		i_error("close(epoll) failed: %m");
 	array_free(&ioloop->handler_context->fd_index);
-	p_free(ioloop->pool, ioloop->handler_context->events);
+	array_free(&ioloop->handler_context->events);
 	p_free(ioloop->pool, ioloop->handler_context);
 }
 
@@ -83,7 +63,7 @@
 	int events = 0, i;
 	struct io *io;
 
-	for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
+	for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
 		io = list->ios[i];
 
 		if (io == NULL)
@@ -100,80 +80,38 @@
 	return events;
 }
 
-static bool iolist_add(struct io_list *list, struct io *io)
-{
-	int i, idx;
-
-	if ((io->condition & IO_READ) != 0)
-		idx = EPOLL_LIST_INPUT;
-	else if ((io->condition & IO_WRITE) != 0)
-		idx = EPOLL_LIST_OUTPUT;
-	else if ((io->condition & IO_ERROR) != 0)
-		idx = EPOLL_LIST_ERROR;
-	else {
-		i_unreached();
-	}
-
-	i_assert(list->ios[idx] == NULL);
-	list->ios[idx] = io;
-
-	/* check if this was the first one */
-	for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
-		if (i != idx && list->ios[i] != NULL)
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-static bool iolist_del(struct io_list *list, struct io *io)
-{
-	bool last = TRUE;
-	int i;
-
-	for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
-		if (list->ios[i] != NULL) {
-			if (list->ios[i] == io)
-				list->ios[i] = NULL;
-			else
-				last = FALSE;
-		}
-	}
-	return last;
-}
-
 void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct io_list **list;
 	struct epoll_event event;
-	int ret, op, fd = io->fd;
+	int op;
 	bool first;
 
-	list = array_idx_modifyable(&ctx->fd_index, fd);
+	list = array_idx_modifyable(&ctx->fd_index, io->fd);
 	if (*list == NULL)
 		*list = p_new(ioloop->pool, struct io_list, 1);
 
-	first = iolist_add(*list, io);
+	first = ioloop_iolist_add(*list, io);
 
 	event.data.ptr = *list;
 	event.events = epoll_event_mask(*list);
 
 	op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
 
-	ret = epoll_ctl(ctx->epfd, op, fd, &event);
-	if (ret < 0)
-		i_fatal("io_loop_handle_add: epoll_ctl(%d, %d): %m", op, fd);
-
-	if (ctx->events_pos >= ctx->events_size) {
-		ctx->events_size = nearest_power(ctx->events_size + 1);
-
-		p_free(ioloop->pool, ctx->events);
-		ctx->events = p_new(ioloop->pool, struct epoll_event,
-				    ctx->events_size);
+	if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
+		i_fatal("io_loop_handle_add: epoll_ctl(%d, %d): %m",
+			op, io->fd);
 	}
 
-	ctx->events_pos++;
+	if (first) {
+		/* allow epoll_wait() to return the maximum number of events
+		   by keeping space allocated for each file descriptor */
+		if (ctx->deleted_count > 0)
+			ctx->deleted_count--;
+		else
+			(void)array_append_space(&ctx->events);
+	}
 }
 
 void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
@@ -181,24 +119,28 @@
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct io_list **list;
 	struct epoll_event event;
-	int ret, op;
+	int op;
 	bool last;
 
 	list = array_idx_modifyable(&ctx->fd_index, io->fd);
-	last = iolist_del(*list, io);
+	last = ioloop_iolist_del(*list, io);
 
 	event.data.ptr = *list;
 	event.events = epoll_event_mask(*list);
 
 	op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
 
-	ret = epoll_ctl(ctx->epfd, op, io->fd, &event);
-	if (ret < 0 && errno != EBADF) {
-		i_fatal("io_loop_handle_remove: epoll_ctl(%d, %d): %m",
+	if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
+		i_error("io_loop_handle_remove: epoll_ctl(%d, %d): %m",
 			op, io->fd);
 	}
 
-	ctx->events_pos--;
+	if (last) {
+		/* since we're not freeing memory in any case, just increase
+		   deleted counter so next handle_add() can just decrease it
+		   insteading of appending to the events array */
+		ctx->deleted_count++;
+	}
 }
 
 void io_loop_handler_run(struct ioloop *ioloop)
@@ -208,14 +150,15 @@
 	struct io_list *list;
 	struct io *io;
 	struct timeval tv;
-	unsigned int t_id;
+	unsigned int events_count, t_id;
 	int msecs, ret, i;
 	bool call;
 
         /* get the time left for next timeout task */
 	msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
 
-	ret = epoll_wait(ctx->epfd, ctx->events, ctx->events_size, msecs);
+	event = array_get_modifyable(&ctx->events, &events_count);
+	ret = epoll_wait(ctx->epfd, event, events_count, msecs);
 	if (ret < 0 && errno != EINTR)
 		i_fatal("epoll_wait(): %m");
 
@@ -227,11 +170,10 @@
 		return;
 	}
 
-	event = ctx->events;
 	while (ret-- > 0) {
 		list = event->data.ptr;
 
-		for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
+		for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
 			io = list->ios[i];
 			if (io == NULL)
 				continue;

Index: ioloop-internal.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-internal.h,v
retrieving revision 1.16
retrieving revision 1.16.2.1
diff -u -d -r1.16 -r1.16.2.1
--- ioloop-internal.h	29 Jan 2006 10:55:22 -0000	1.16
+++ ioloop-internal.h	16 Aug 2006 15:54:56 -0000	1.16.2.1
@@ -3,6 +3,10 @@
 
 #include "ioloop.h"
 
+#ifndef IOLOOP_INITIAL_FD_COUNT
+#  define IOLOOP_INITIAL_FD_COUNT 128
+#endif
+
 struct ioloop {
         struct ioloop *prev;
 

--- NEW FILE: ioloop-iolist.c ---
/*
 * Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
 *
 * This software is released under the MIT license.
 */

#include "lib.h"
#include "ioloop-internal.h"
#include "ioloop-iolist.h"

bool ioloop_iolist_add(struct io_list *list, struct io *io)
{
	int i, idx;

	if ((io->condition & IO_READ) != 0)
		idx = IOLOOP_IOLIST_INPUT;
	else if ((io->condition & IO_WRITE) != 0)
		idx = IOLOOP_IOLIST_OUTPUT;
	else if ((io->condition & IO_ERROR) != 0)
		idx = IOLOOP_IOLIST_ERROR;
	else {
		i_unreached();
	}

	i_assert(list->ios[idx] == NULL);
	list->ios[idx] = io;

	/* check if this was the first one */
	for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
		if (i != idx && list->ios[i] != NULL)
			return FALSE;
	}

	return TRUE;
}

bool ioloop_iolist_del(struct io_list *list, struct io *io)
{
	bool last = TRUE;
	int i;

	for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
		if (list->ios[i] != NULL) {
			if (list->ios[i] == io)
				list->ios[i] = NULL;
			else
				last = FALSE;
		}
	}
	return last;
}

--- NEW FILE: ioloop-iolist.h ---
#ifndef __IOLOOP_IOLIST_H
#define __IOLOOP_IOLIST_H

enum {
	IOLOOP_IOLIST_INPUT,
	IOLOOP_IOLIST_OUTPUT,
	IOLOOP_IOLIST_ERROR,

	IOLOOP_IOLIST_IOS_PER_FD
};

struct io_list {
	struct io *ios[IOLOOP_IOLIST_IOS_PER_FD];
};

bool ioloop_iolist_add(struct io_list *list, struct io *io);
bool ioloop_iolist_del(struct io_list *list, struct io *io);

#endif

Index: ioloop-kqueue.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-kqueue.c,v
retrieving revision 1.4.2.1
retrieving revision 1.4.2.2
diff -u -d -r1.4.2.1 -r1.4.2.2
--- ioloop-kqueue.c	10 May 2006 15:48:04 -0000	1.4.2.1
+++ ioloop-kqueue.c	16 Aug 2006 15:54:56 -0000	1.4.2.2
@@ -9,38 +9,27 @@
  * (at your option) any later version.
  */
 
-/* @UNSAFE: whole file */
-
 #include "lib.h"
 
 #ifdef IOLOOP_KQUEUE
 
+#include "array.h"
 #include "fd-close-on-exec.h"
 #include "ioloop-internal.h"
+#include "ioloop-iolist.h"
+
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/time.h>
 
-#ifndef INITIAL_BUF_SIZE
-#  define INITIAL_BUF_SIZE 128
-#endif
-
-#define MASK (IO_READ | IO_WRITE | IO_ERROR)
-
 struct ioloop_handler_context {
 	int kq;
-	size_t evbuf_size;
-	struct kevent *evbuf;
-
-	size_t fds_size;
-	struct fdrecord *fds;
-};
 
-struct fdrecord {
-	struct io *errio;
-	enum io_condition mode;
+	unsigned int deleted_count;
+	array_t ARRAY_DEFINE(fd_index, struct io_list *);
+	array_t ARRAY_DEFINE(events, struct kevent);
 };
 
 void io_loop_handler_init(struct ioloop *ioloop)
@@ -50,117 +39,119 @@
 	ioloop->handler_context = ctx =
 		p_new(ioloop->pool, struct ioloop_handler_context, 1);
 
-	ctx->evbuf_size = INITIAL_BUF_SIZE;
-	ctx->evbuf = p_new(ioloop->pool, struct kevent, ctx->evbuf_size);
 	ctx->kq = kqueue();
 	if (ctx->kq < 0)
 		i_fatal("kqueue() in io_loop_handler_init() failed: %m");
 	fd_close_on_exec(ctx->kq, TRUE);
 
-	ctx->fds_size = INITIAL_BUF_SIZE;
-	ctx->fds = p_new(ioloop->pool, struct fdrecord, ctx->fds_size);
+	ARRAY_CREATE(&ctx->events, ioloop->pool, struct kevent,
+		     IOLOOP_INITIAL_FD_COUNT);
+	ARRAY_CREATE(&ctx->fd_index, ioloop->pool,
+		     struct io_list *, IOLOOP_INITIAL_FD_COUNT);
 }
 
 void io_loop_handler_deinit(struct ioloop *ioloop)
 {
 	if (close(ioloop->handler_context->kq) < 0)
 		i_error("close(kqueue) in io_loop_handler_deinit() failed: %m");
-	p_free(ioloop->pool, ioloop->handler_context->evbuf);
-	p_free(ioloop->pool, ioloop->handler_context->fds);
+	array_free(&ioloop->handler_context->fd_index);
+	array_free(&ioloop->handler_context->events);
 	p_free(ioloop->pool, ioloop->handler_context);
 }
 
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+static int io_filter(struct io *io)
 {
-	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	const int fd = io->fd;
-	struct kevent ev = { fd, 0, EV_ADD, 0, 0, NULL };
-	enum io_condition condition = io->condition & MASK;
-	
-	i_assert(io->callback != NULL);
+	int filter = 0;
 
-	/* grow ctx->fds array if necessary */
-	if ((size_t)fd >= ctx->fds_size) {
-		size_t old_size = ctx->fds_size;
+	if ((io->condition & (IO_READ | IO_ERROR)) != 0)
+		filter |= EVFILT_READ;
+	if ((io->condition & (IO_WRITE | IO_ERROR)) != 0)
+		filter |= EVFILT_WRITE;
 
-		ctx->fds_size = nearest_power((unsigned int)fd+1);
-		i_assert(ctx->fds_size < (size_t)-1 / sizeof(int));
+	return filter;
+}
 
-		ctx->fds = p_realloc(ioloop->pool, ctx->fds,
-				     sizeof(struct fdrecord) * old_size,
-				     sizeof(struct fdrecord) * ctx->fds_size);
-		memset(ctx->fds + old_size, 0,
-		       sizeof(struct fdrecord) * (ctx->fds_size - old_size));
-	}
+static int io_list_filter(struct io_list *list)
+{
+	int filter = 0, i;
+	struct io *io;
 
-	if (condition & (IO_READ | IO_WRITE))
-		ev.udata = io;
-	if (condition & IO_ERROR)
-		ctx->fds[fd].errio = io;
+	for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
+		io = list->ios[i];
 
-	if (condition & (IO_READ | IO_ERROR)) {
-		ctx->fds[fd].mode |= condition;
-		ev.filter = EVFILT_READ;
-		if (!(condition & ~IO_ERROR))
-			ev.flags |= EV_CLEAR;
-		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
-			i_error("kevent(%d) in io_loop_handle_add() failed: %m",
-				fd);
-		}
+		if (io == NULL)
+			continue;
+
+		if ((io->condition & (IO_READ | IO_ERROR)) != 0)
+			filter |= EVFILT_READ;
+		if ((io->condition & (IO_WRITE | IO_ERROR)) != 0)
+			filter |= EVFILT_WRITE;
 	}
-	if (condition & (IO_WRITE | IO_ERROR)) {
-		ctx->fds[fd].mode |= condition;
-		ev.filter = EVFILT_WRITE;
-		if (!(condition & ~IO_ERROR))
-			ev.flags |= EV_CLEAR;
-		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
-			i_error("kevent(%d) in io_loop_handle_add() failed: %m",
-				fd);
-		}
+
+	return filter;
+}
+
+void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+{
+	struct ioloop_handler_context *ctx = ioloop->handler_context;
+	struct io_list **list;
+	struct kevent ev;
+	bool first;
+
+	list = array_idx_modifyable(&ctx->fd_index, io->fd);
+	if (*list == NULL)
+		*list = p_new(ioloop->pool, struct io_list, 1);
+
+	first = ioloop_iolist_add(*list, io);
+
+	EV_SET(ev, io->fd, io_filter(io), EV_ADD, 0, 0, *list);
+	if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
+		i_fatal("kevent(EV_ADD, %d) failed: %m", io->fd);
+
+	if (first) {
+		/* allow kevent() to return the maximum number of events
+		   by keeping space allocated for each file descriptor */
+		if (ctx->deleted_count > 0)
+			ctx->deleted_count--;
+		else
+			(void)array_append_space(&ctx->events);
 	}
 }
 
 void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	const int fd = io->fd;
-	struct kevent ev = { fd, 0, EV_DELETE, 0, 0, NULL };
-	struct fdrecord *const fds = ctx->fds;
-	const enum io_condition condition = io->condition & MASK;
+	struct io_list **list;
+	struct kevent ev;
+	int filter;
+	bool last;
+	
+	list = array_idx_modifyable(&ctx->fd_index, io->fd);
+	last = ioloop_iolist_del(*list, io);
 
-	i_assert((size_t)fd < ctx->fds_size);
+	filter = io_filter(io) & ~io_list_filter(*list);
+	EV_SET(ev, io->fd, filter, EV_DELETE, 0, 0, *list);
+	if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
+		i_error("kevent(EV_DELETE, %d) failed: %m", io->fd);
 
-	if (condition & IO_ERROR)
-		fds[fd].errio = NULL;
-	if (condition & (IO_READ | IO_ERROR)) {
-		ev.filter = EVFILT_READ;
-		fds[fd].mode &= ~condition;
-		if ((fds[fd].mode & (IO_READ | IO_ERROR)) == 0) {
-			if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
-				i_error("kevent(%d) in io_loop_handle_remove "
-					"failed: %m", fd);
-			}
-		}
-	}
-	if (condition & (IO_WRITE | IO_ERROR)) {
-		ev.filter = EVFILT_WRITE;
-		fds[fd].mode &= ~condition;
-		if ((fds[fd].mode & (IO_WRITE | IO_ERROR)) == 0) {
-			if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
-				i_error("kevent(%d) in io_loop_handle_remove "
-					"failed: %m", fd);
-			}
-		}
+	if (last) {
+		/* since we're not freeing memory in any case, just increase
+		   deleted counter so next handle_add() can just decrease it
+		   insteading of appending to the events array */
+		ctx->deleted_count++;
 	}
 }
 
 void io_loop_handler_run(struct ioloop *ioloop)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
+	struct kevent *event;
 	struct timeval tv;
 	struct timespec ts;
-	unsigned int t_id;
+	struct io_list *list;
+	unsigned int events_count, t_id;
 	int msecs, ret, i;
+	bool call, called;
 
 	/* get the time left for next timeout task */
 	msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
@@ -168,7 +159,8 @@
 	ts.tv_nsec = tv.tv_usec * 1000;
 
 	/* wait for events */
-	ret = kevent (ctx->kq, NULL, 0, ctx->evbuf, ctx->evbuf_size, &ts);
+	event = array_get_modifyable(&ctx->events, &events_count);
+	ret = kevent (ctx->kq, NULL, 0, event, events_count, &ts);
 	if (ret < 0 && errno != EINTR)
 		i_fatal("kevent(): %m");
 
@@ -180,49 +172,52 @@
 		return;
 	}
 
-	i_assert((size_t)ret <= ctx->evbuf_size);
-
 	/* loop through all received events */
-	for (i = 0; i < ret; ++i) {
-		struct io *io = ctx->evbuf[i].udata;
+	while (ret-- > 0) {
+		list = (void *)event->udata;
 
-		i_assert(ctx->evbuf[i].ident < ctx->fds_size);
-		if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
-		    (ctx->evbuf[i].flags & (EV_EOF | EV_ERROR))) {
-			struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
+		called = FALSE;
+		for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
+			struct io *io = list->ios[i];
+			if (io == NULL)
+				continue;
 
-			t_id = t_push();
-			errio->callback(errio->context);
-			if (t_pop() != t_id) {
-				i_panic("Leaked a t_pop() call"
-					" in I/O handler %p",
-					(void *)errio->callback);
-			}
-		} else if (ctx->fds[ctx->evbuf[i].ident].mode
-			 & (IO_WRITE | IO_READ)) {
-			t_id = t_push();
-			io->callback(io->context);
-			if (t_pop() != t_id) {
-				i_panic("Leaked a t_pop() call"
-					" in I/O handler %p",
-					(void *)io->callback);
+			call = FALSE;
+			if ((event->flags & EV_ERROR) != 0) {
+				errno = event->data;
+				i_error("kevent(): invalid fd %d callback "
+					"%p: %m", io->fd, (void *)io->callback);
+			} else if ((event->flags & EV_EOF) != 0)
+				call = TRUE;
+			else if ((io->condition & IO_READ) != 0)
+				call = (event->filter & EVFILT_READ) != 0;
+			else if ((io->condition & IO_WRITE) != 0)
+				call = (event->filter & EVFILT_WRITE) != 0;
+
+			if (call) {
+				called = TRUE;
+				t_id = t_push();
+				io->callback(io->context);
+				if (t_pop() != t_id) {
+					i_panic("Leaked a t_pop() call in "
+						"I/O handler %p",
+						(void *)io->callback);
+				}
 			}
-		} else if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
-			/* 
-			   NO-OP. If the handle is registered only for 
-			   IO_ERROR, then we can get readable/writable event
-			   but no IO_READ | IO_WRITE set.
-			 */
-		} else
-			i_panic("Unrecognized event: kevent {.ident =  %u,"
-                                " .filter = 0x%04x,"
-                                " .flags = 0x%04x,"
-                                " .fflags = 0x%08x,"
-                                " .data = 0x%08x}\n"
-				"mode: 0x%x04x", ctx->evbuf[i].ident,
-                                ctx->evbuf[i].filter, ctx->evbuf[i].flags,
-                                ctx->evbuf[i].fflags, ctx->evbuf[i].data,
-				ctx->fds[ctx->evbuf[i].ident].mode);
+		}
+		if (!called) {
+			i_panic("Unrecognized event: kevent "
+				"{.ident = %d,"
+				" .filter = 0x%04x,"
+				" .flags = 0x%04x,"
+				" .fflags = 0x%08x,"
+				" .data = 0x%08llx}, io filter = %x",
+				event->ident,
+				event->filter, event->flags,
+				event->fflags, (unsigned long long)event->data,
+				io_list_filter(list));
+		}
+		event++;
 	}
 }
 

Index: ioloop-notify-kqueue.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-kqueue.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -u -d -r1.3 -r1.3.2.1
--- ioloop-notify-kqueue.c	29 Jan 2006 10:55:22 -0000	1.3
+++ ioloop-notify-kqueue.c	16 Aug 2006 15:54:56 -0000	1.3.2.1
@@ -33,13 +33,22 @@
 	struct ioloop_notify_handler_context *ctx = context;
 	struct io *io;
 	struct kevent ev;
+	struct timespec ts;
 
 	if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
 		i_fatal("gettimeofday() failed: %m");
 	ioloop_time = ioloop_timeval.tv_sec;
 
-	if (kevent(ctx->kq, NULL, 0, &ev, 1, 0) < 0)
-		i_fatal("kevent() failed: %m");
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+
+	ret = kevent(ctx->kq, NULL, 0, &ev, 1, &ts);
+	if (ret <= 0) {
+		if (ret == 0 || errno == EINTR)
+			return;
+
+		i_fatal("kevent(notify) failed: %m");
+	}
 	io = ev.udata;
 	io->callback(io->context);
 }
@@ -52,7 +61,7 @@
 		p_new(ioloop->pool, struct ioloop_notify_handler_context, 1);
 	ctx->kq = kqueue();
 	if (ctx->kq < 0)
-		i_fatal("kqueue() in io_loop_notify_handler_init() failed: %m");
+		i_fatal("kqueue(notify) failed: %m");
 	fd_close_on_exec(ctx->kq, TRUE);
 }
 
@@ -73,18 +82,15 @@
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct kevent ev = { -1, EVFILT_VNODE, EV_ADD,
-			     NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
-			     | NOTE_REVOKE, 0, NULL };
+	struct kevent ev;
 	struct io *io;
 	int fd;
 	struct stat sb;
 
-	i_assert(callback != NULL);
-
 	fd = open(path, O_RDONLY);
 	if (fd == -1) {
-		i_error("open(%s) for kq notify failed: %m", path);
+		if (errno != ENOENT)
+			i_error("open(%s) for kq notify failed: %m", path);
 		return NULL;
 	}
 
@@ -103,10 +109,12 @@
 	io->fd = fd;
 	io->callback = callback;
 	io->context = context;
-	ev.ident = fd;
-	ev.udata = io;
+
+	EV_SET(ev, fd, EVFILT_VNODE, EV_ADD,
+	       NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_REVOKE, 0, io);
 	if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
 		i_error("kevent(%d, %s) for notify failed: %m", fd, path);
+		(void)close(fd);
 		p_free(ioloop->pool, io);
 		return NULL;
 	}
@@ -123,14 +131,15 @@
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct kevent ev = { io->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL };
+	struct kevent ev;
 
 	i_assert((io->condition & IO_NOTIFY) != 0);
 
+	EV_SET(ev, io->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
 	if (kevent(ctx->kq, &ev, 1, NULL, 0, 0) < 0)
 		i_error("kevent(%d) for notify remove failed: %m", io->fd);
 	if (close(io->fd) < 0)
-		i_error("close(%d) failed: %m", io->fd);
+		i_error("close(%d) for notify remove failed: %m", io->fd);
 }
 
 #endif

Index: ioloop-poll.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-poll.c,v
retrieving revision 1.32
retrieving revision 1.32.2.1
diff -u -d -r1.32 -r1.32.2.1
--- ioloop-poll.c	29 Jan 2006 12:21:06 -0000	1.32
+++ ioloop-poll.c	16 Aug 2006 15:54:56 -0000	1.32.2.1
@@ -10,10 +10,6 @@
 #include <fcntl.h>
 #include <sys/poll.h>
 
-#ifndef INITIAL_POLL_FDS
-#  define INITIAL_POLL_FDS 128
-#endif
-
 struct ioloop_handler_context {
 	unsigned int fds_count, fds_pos;
 	struct pollfd *fds;
@@ -28,10 +24,10 @@
 
 	ioloop->handler_context = ctx =
 		p_new(ioloop->pool, struct ioloop_handler_context, 1);
-	ctx->fds_count = INITIAL_POLL_FDS;
+	ctx->fds_count = IOLOOP_INITIAL_FD_COUNT;
 	ctx->fds = p_new(ioloop->pool, struct pollfd, ctx->fds_count);
 
-	ctx->idx_count = INITIAL_POLL_FDS;
+	ctx->idx_count = IOLOOP_INITIAL_FD_COUNT;
 	ctx->fd_index = p_new(ioloop->pool, int, ctx->idx_count);
         memset(ctx->fd_index, 0xff, sizeof(int) * ctx->idx_count);
 }



More information about the dovecot-cvs mailing list