[dovecot-cvs] dovecot/src/lib Makefile.am, 1.69, 1.70 ioloop-epoll.c, 1.20, 1.21 ioloop-internal.h, 1.18, 1.19 ioloop-iolist.c, 1.2, 1.3 ioloop-iolist.h, 1.2, 1.3 ioloop-kqueue.c, 1.15, 1.16 ioloop-notify-dn.c, 1.18, 1.19 ioloop-notify-fd.c, NONE, 1.1 ioloop-notify-fd.h, NONE, 1.1 ioloop-notify-inotify.c, 1.12, 1.13 ioloop-notify-kqueue.c, 1.8, 1.9 ioloop-poll.c, 1.34, 1.35 ioloop-select.c, 1.24, 1.25 ioloop.c, 1.43, 1.44 ioloop.h, 1.20, 1.21

tss at dovecot.org tss at dovecot.org
Fri Mar 9 00:04:24 EET 2007


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

Modified Files:
	Makefile.am ioloop-epoll.c ioloop-internal.h ioloop-iolist.c 
	ioloop-iolist.h ioloop-kqueue.c ioloop-notify-dn.c 
	ioloop-notify-inotify.c ioloop-notify-kqueue.c ioloop-poll.c 
	ioloop-select.c ioloop.c ioloop.h 
Added Files:
	ioloop-notify-fd.c ioloop-notify-fd.h 
Log Message:
Various cleanups to ioloop code.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -d -r1.69 -r1.70
--- Makefile.am	22 Feb 2007 21:50:49 -0000	1.69
+++ Makefile.am	8 Mar 2007 22:04:21 -0000	1.70
@@ -37,6 +37,7 @@
 	ioloop.c \
 	ioloop-iolist.c \
 	ioloop-notify-none.c \
+	ioloop-notify-fd.c \
 	ioloop-notify-dn.c \
 	ioloop-notify-inotify.c \
 	ioloop-notify-kqueue.c \
@@ -124,6 +125,7 @@
 	ioloop.h \
 	ioloop-iolist.h \
 	ioloop-internal.h \
+	ioloop-notify-fd.h \
 	lib.h \
 	lib-signals.h \
 	macros.h \

Index: ioloop-epoll.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-epoll.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- ioloop-epoll.c	3 Dec 2006 14:27:57 -0000	1.20
+++ ioloop-epoll.c	8 Mar 2007 22:04:21 -0000	1.21
@@ -29,11 +29,10 @@
 {
 	struct ioloop_handler_context *ctx;
 
-	ioloop->handler_context = ctx =
-		p_new(ioloop->pool, struct ioloop_handler_context, 1);
+	ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
 
-	p_array_init(&ctx->events, ioloop->pool, IOLOOP_INITIAL_FD_COUNT);
-	p_array_init(&ctx->fd_index, ioloop->pool, IOLOOP_INITIAL_FD_COUNT);
+	i_array_init(&ctx->events, IOLOOP_INITIAL_FD_COUNT);
+	i_array_init(&ctx->fd_index, IOLOOP_INITIAL_FD_COUNT);
 
 	ctx->epfd = epoll_create(IOLOOP_INITIAL_FD_COUNT);
 	if (ctx->epfd < 0)
@@ -49,13 +48,13 @@
 
 	list = array_get_modifiable(&ctx->fd_index, &count);
 	for (i = 0; i < count; i++)
-		p_free(ioloop->pool, list[i]);
+		i_free(list[i]);
 
 	if (close(ctx->epfd) < 0)
 		i_error("close(epoll) failed: %m");
 	array_free(&ioloop->handler_context->fd_index);
 	array_free(&ioloop->handler_context->events);
-	p_free(ioloop->pool, ioloop->handler_context);
+	i_free(ioloop->handler_context);
 }
 
 #define IO_EPOLL_ERROR (EPOLLERR | EPOLLHUP)
@@ -65,7 +64,7 @@
 static int epoll_event_mask(struct io_list *list)
 {
 	int events = 0, i;
-	struct io *io;
+	struct io_file *io;
 
 	for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
 		io = list->ios[i];
@@ -73,18 +72,18 @@
 		if (io == NULL)
 			continue;
 
-		if (io->condition & IO_READ)
+		if (io->io.condition & IO_READ)
 			events |= IO_EPOLL_INPUT;
-		if (io->condition & IO_WRITE)
+		if (io->io.condition & IO_WRITE)
 			events |= IO_EPOLL_OUTPUT;
-		if (io->condition & IO_ERROR)
+		if (io->io.condition & IO_ERROR)
 			events |= IO_EPOLL_ERROR;
 	}
 
 	return events;
 }
 
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct io_list **list;
@@ -94,7 +93,7 @@
 
 	list = array_idx_modifiable(&ctx->fd_index, io->fd);
 	if (*list == NULL)
-		*list = p_new(ioloop->pool, struct io_list, 1);
+		*list = i_new(struct io_list, 1);
 
 	first = ioloop_iolist_add(*list, io);
 
@@ -119,7 +118,7 @@
 	}
 }
 
-void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct io_list **list;
@@ -147,6 +146,7 @@
 		   insteading of appending to the events array */
 		ctx->deleted_count++;
 	}
+	i_free(io);
 }
 
 void io_loop_handler_run(struct ioloop *ioloop)
@@ -155,7 +155,7 @@
 	struct epoll_event *events;
 	const struct epoll_event *event;
 	struct io_list *list;
-	struct io *io;
+	struct io_file *io;
 	struct timeval tv;
 	unsigned int events_count, t_id;
 	int msecs, ret, i, j;
@@ -189,20 +189,20 @@
 			call = FALSE;
 			if ((event->events & (EPOLLHUP | EPOLLERR)) != 0)
 				call = TRUE;
-			else if ((io->condition & IO_READ) != 0)
+			else if ((io->io.condition & IO_READ) != 0)
 				call = (event->events & EPOLLIN) != 0;
-			else if ((io->condition & IO_WRITE) != 0)
+			else if ((io->io.condition & IO_WRITE) != 0)
 				call = (event->events & EPOLLOUT) != 0;
-			else if ((io->condition & IO_ERROR) != 0)
+			else if ((io->io.condition & IO_ERROR) != 0)
 				call = (event->events & IO_EPOLL_ERROR) != 0;
 
 			if (call) {
 				t_id = t_push();
-				io->callback(io->context);
+				io->io.callback(io->io.context);
 				if (t_pop() != t_id) {
 					i_panic("Leaked a t_pop() call in "
 						"I/O handler %p",
-						(void *)io->callback);
+						(void *)io->io.callback);
 				}
 			}
 		}

Index: ioloop-internal.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-internal.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- ioloop-internal.h	17 Aug 2006 18:46:42 -0000	1.18
+++ ioloop-internal.h	8 Mar 2007 22:04:21 -0000	1.19
@@ -10,11 +10,8 @@
 struct ioloop {
         struct ioloop *prev;
 
-	pool_t pool;
-
-	struct io *ios;
-	struct io *notifys;
-	struct io *next_io;
+	struct io_file *io_files;
+	struct io_file *next_io_file;
 	struct timeout *timeouts; /* sorted by next_run */
 
         struct ioloop_handler_context *handler_context;
@@ -24,18 +21,22 @@
 };
 
 struct io {
-	/* use a doubly linked list so that io_remove() is quick */
-	struct io *prev, *next;
-
-	int refcount;
-
-	int fd;
 	enum io_condition condition;
 
 	io_callback_t *callback;
         void *context;
 };
 
+struct io_file {
+	struct io io;
+
+	/* use a doubly linked list so that io_remove() is quick */
+	struct io_file *prev, *next;
+
+	int refcount;
+	int fd;
+};
+
 struct timeout {
 	struct timeout *next;
 
@@ -53,21 +54,14 @@
 			  struct timeval *tv_now);
 void io_loop_handle_timeouts(struct ioloop *ioloop);
 
-/* call only when timeout->destroyed is TRUE */
-void timeout_destroy(struct ioloop *ioloop, struct timeout **timeout_p);
-
 /* I/O handler calls */
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io);
-void io_loop_handle_remove(struct ioloop *ioloop, struct io *io);
+void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io);
+void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io);
 
 void io_loop_handler_init(struct ioloop *ioloop);
 void io_loop_handler_deinit(struct ioloop *ioloop);
 
-void io_loop_notify_handler_init(struct ioloop *ioloop);
-void io_loop_notify_handler_deinit(struct ioloop *ioloop);
-
-struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
-			      io_callback_t *callback, void *context);
 void io_loop_notify_remove(struct ioloop *ioloop, struct io *io);
+void io_loop_notify_handler_deinit(struct ioloop *ioloop);
 
 #endif

Index: ioloop-iolist.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-iolist.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ioloop-iolist.c	16 Aug 2006 15:54:58 -0000	1.2
+++ ioloop-iolist.c	8 Mar 2007 22:04:21 -0000	1.3
@@ -8,15 +8,15 @@
 #include "ioloop-internal.h"
 #include "ioloop-iolist.h"
 
-bool ioloop_iolist_add(struct io_list *list, struct io *io)
+bool ioloop_iolist_add(struct io_list *list, struct io_file *io)
 {
 	int i, idx;
 
-	if ((io->condition & IO_READ) != 0)
+	if ((io->io.condition & IO_READ) != 0)
 		idx = IOLOOP_IOLIST_INPUT;
-	else if ((io->condition & IO_WRITE) != 0)
+	else if ((io->io.condition & IO_WRITE) != 0)
 		idx = IOLOOP_IOLIST_OUTPUT;
-	else if ((io->condition & IO_ERROR) != 0)
+	else if ((io->io.condition & IO_ERROR) != 0)
 		idx = IOLOOP_IOLIST_ERROR;
 	else {
 		i_unreached();
@@ -34,7 +34,7 @@
 	return TRUE;
 }
 
-bool ioloop_iolist_del(struct io_list *list, struct io *io)
+bool ioloop_iolist_del(struct io_list *list, struct io_file *io)
 {
 	bool last = TRUE;
 	int i;

Index: ioloop-iolist.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-iolist.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ioloop-iolist.h	16 Aug 2006 15:54:58 -0000	1.2
+++ ioloop-iolist.h	8 Mar 2007 22:04:21 -0000	1.3
@@ -10,10 +10,10 @@
 };
 
 struct io_list {
-	struct io *ios[IOLOOP_IOLIST_IOS_PER_FD];
+	struct io_file *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);
+bool ioloop_iolist_add(struct io_list *list, struct io_file *io);
+bool ioloop_iolist_del(struct io_list *list, struct io_file *io);
 
 #endif

Index: ioloop-kqueue.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-kqueue.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- ioloop-kqueue.c	3 Dec 2006 14:27:57 -0000	1.15
+++ ioloop-kqueue.c	8 Mar 2007 22:04:21 -0000	1.16
@@ -37,22 +37,20 @@
 	int kq;
 
 	unsigned int deleted_count;
-	array_t ARRAY_DEFINE(events, struct kevent);
+	ARRAY_DEFINE(events, struct kevent);
 };
 
 void io_loop_handler_init(struct ioloop *ioloop)
 {
 	struct ioloop_handler_context *ctx;
 
-	ioloop->handler_context = ctx =
-		p_new(ioloop->pool, struct ioloop_handler_context, 1);
-
+	ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
 	ctx->kq = kqueue();
 	if (ctx->kq < 0)
 		i_fatal("kqueue() in io_loop_handler_init() failed: %m");
 	fd_close_on_exec(ctx->kq, TRUE);
 
-	p_array_init(&ctx->events, ioloop->pool, IOLOOP_INITIAL_FD_COUNT);
+	i_array_init(&ctx->events, IOLOOP_INITIAL_FD_COUNT);
 }
 
 void io_loop_handler_deinit(struct ioloop *ioloop)
@@ -60,20 +58,20 @@
 	if (close(ioloop->handler_context->kq) < 0)
 		i_error("close(kqueue) in io_loop_handler_deinit() failed: %m");
 	array_free(&ioloop->handler_context->events);
-	p_free(ioloop->pool, ioloop->handler_context);
+	i_free(ioloop->handler_context);
 }
 
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct kevent ev;
 
-	if ((io->condition & (IO_READ | IO_ERROR)) != 0) {
+	if ((io->io.condition & (IO_READ | IO_ERROR)) != 0) {
 		MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_ADD, 0, 0, io);
 		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
 			i_fatal("kevent(EV_ADD, %d) failed: %m", io->fd);
 	}
-	if ((io->condition & IO_WRITE) != 0) {
+	if ((io->io.condition & IO_WRITE) != 0) {
 		MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_ADD, 0, 0, io);
 		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
 			i_fatal("kevent(EV_ADD, %d) failed: %m", io->fd);
@@ -87,17 +85,17 @@
 		(void)array_append_space(&ctx->events);
 }
 
-void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct kevent ev;
 
-	if ((io->condition & (IO_READ | IO_ERROR)) != 0) {
+	if ((io->io.condition & (IO_READ | IO_ERROR)) != 0) {
 		MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
 		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
 			i_error("kevent(EV_DELETE, %d) failed: %m", io->fd);
 	}
-	if ((io->condition & IO_WRITE) != 0) {
+	if ((io->io.condition & IO_WRITE) != 0) {
 		MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
 		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
 			i_error("kevent(EV_DELETE, %d) failed: %m", io->fd);
@@ -107,6 +105,10 @@
 	   deleted counter so next handle_add() can just decrease it
 	   insteading of appending to the events array */
 	ctx->deleted_count++;
+
+	i_assert(io->refcount > 0);
+	if (--io->refcount == 0)
+		i_free(io);
 }
 
 void io_loop_handler_run(struct ioloop *ioloop)
@@ -116,7 +118,7 @@
 	const struct kevent *event;
 	struct timeval tv;
 	struct timespec ts;
-	struct io *io;
+	struct io_file *io;
 	unsigned int events_count, t_id;
 	int msecs, ret, i;
 
@@ -147,19 +149,19 @@
 		io = (void *)event->udata;
 
 		/* callback is NULL if io_remove() was already called */
-		if (io->callback != NULL) {
+		if (io->io.callback != NULL) {
 			t_id = t_push();
-			io->callback(io->context);
+			io->io.callback(io->io.context);
 			if (t_pop() != t_id) {
 				i_panic("Leaked a t_pop() call in "
 					"I/O handler %p",
-					(void *)io->callback);
+					(void *)io->io.callback);
 			}
 		}
 
 		i_assert(io->refcount > 0);
 		if (--io->refcount == 0)
-			p_free(current_ioloop->pool, io);
+			i_free(io);
 	}
 }
 

Index: ioloop-notify-dn.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-dn.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- ioloop-notify-dn.c	17 Jan 2007 17:59:13 -0000	1.18
+++ ioloop-notify-dn.c	8 Mar 2007 22:04:21 -0000	1.19
@@ -8,6 +8,7 @@
 #ifdef IOLOOP_NOTIFY_DNOTIFY
 
 #include "ioloop-internal.h"
+#include "ioloop-notify-fd.h"
 #include "fd-set-nonblock.h"
 #include "fd-close-on-exec.h"
 
@@ -16,14 +17,18 @@
 #include <fcntl.h>
 
 struct ioloop_notify_handler_context {
-	struct io *event_io;
-	bool disabled;
+	struct ioloop_notify_fd_context fd_ctx;
 
+	struct io *event_io;
 	int event_pipe[2];
+
+	bool disabled;
 };
 
 static int sigrt_refcount = 0;
 
+static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void);
+
 static void sigrt_handler(int signo __attr_unused__, siginfo_t *si,
 			  void *data __attr_unused__)
 {
@@ -41,41 +46,44 @@
 	errno = saved_errno;
 }
 
-static void event_callback(struct ioloop *ioloop)
+static void dnotify_input(struct ioloop *ioloop)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct io *io;
-	int fd, ret;
+	struct io_notify *io;
+	int fd_buf[256], i, ret;
 
-	ret = read(ctx->event_pipe[0], &fd, sizeof(fd));
+	ret = read(ctx->event_pipe[0], fd_buf, sizeof(fd_buf));
 	if (ret < 0)
 		i_fatal("read(event_pipe) failed: %m");
-	if (ret != sizeof(fd)) {
-		i_fatal("read(event_pipe) returned %d != %"PRIuSIZE_T,
-			ret, sizeof(fd));
-	}
+	if ((ret % sizeof(fd_buf[0])) != 0)
+		i_fatal("read(event_pipe) returned %d", ret);
+	ret /= sizeof(fd_buf[0]);
 
 	if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
 		i_fatal("gettimeofday(): %m");
 	ioloop_time = ioloop_timeval.tv_sec;
 
-	for (io = ioloop->notifys; io != NULL; io = io->next) {
-		if (io->fd == fd) {
-			io->callback(io->context);
-			break;
-		}
+	for (i = 0; i < ret; i++) {
+		io = io_notify_fd_find(&ctx->fd_ctx, fd_buf[i]);
+		if (io != NULL)
+			io->io.callback(io->io.context);
 	}
 }
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
-			      io_callback_t *callback, void *context)
+#undef io_add_notify
+struct io *io_add_notify(const char *path, io_callback_t *callback,
+			 void *context)
 {
 	struct ioloop_notify_handler_context *ctx =
-		ioloop->notify_handler_context;
-	struct io *io;
+		current_ioloop->notify_handler_context;
 	int fd;
 
+	if (ctx == NULL)
+		ctx = io_loop_notify_handler_init();
+	if (ctx->disabled)
+		return NULL;
+
 	fd = open(path, O_RDONLY);
 	if (fd == -1) {
 		i_error("open(%s) for dnotify failed: %m", path);
@@ -109,23 +117,18 @@
 	}
 
 	if (ctx->event_io == NULL) {
-		ctx->event_io =
-			io_add(ctx->event_pipe[0], IO_READ,
-			       event_callback, ioloop);
+		ctx->event_io = io_add(ctx->event_pipe[0], IO_READ,
+				       dnotify_input, current_ioloop);
 	}
 
-	io = p_new(ioloop->pool, struct io, 1);
-	io->fd = fd;
-
-	io->callback = callback;
-        io->context = context;
-	return io;
+	return io_notify_fd_add(&ctx->fd_ctx, fd, callback, context);
 }
 
-void io_loop_notify_remove(struct ioloop *ioloop, struct io *io)
+void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
+	struct io_notify *io = (struct io_notify *)_io;
 
 	if (fcntl(io->fd, F_NOTIFY, 0) < 0)
 		i_error("fcntl(F_NOTIFY, 0) failed: %m");
@@ -134,21 +137,24 @@
 	if (close(io->fd))
 		i_error("close(dnotify) failed: %m");
 
-	if (ioloop->notifys == NULL)
+	io_notify_fd_free(&ctx->fd_ctx, io);
+
+	if (ctx->fd_ctx.notifies == NULL)
 		io_remove(&ctx->event_io);
 }
 
-void io_loop_notify_handler_init(struct ioloop *ioloop)
+static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void)
 {
 	struct ioloop_notify_handler_context *ctx;
 	struct sigaction act;
 
-	ctx = ioloop->notify_handler_context =
+	ctx = current_ioloop->notify_handler_context =
 		i_new(struct ioloop_notify_handler_context, 1);
 
 	if (pipe(ctx->event_pipe) < 0) {
-		i_fatal("pipe() failed: %m");
-		return;
+		ctx->disabled = TRUE;
+		i_error("dnotify: pipe() failed: %m");
+		return ctx;
 	}
 
 	fd_set_nonblock(ctx->event_pipe[0], TRUE);
@@ -175,9 +181,10 @@
 			}
 		}
 	}
+	return ctx;
 }
 
-void io_loop_notify_handler_deinit(struct ioloop *ioloop __attr_unused__)
+void io_loop_notify_handler_deinit(struct ioloop *ioloop)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;

--- NEW FILE: ioloop-notify-fd.c ---
/* Copyright (c) 2007 Timo Sirainen */

#include "lib.h"
#include "ioloop-internal.h"
#include "ioloop-notify-fd.h"

#if defined(IOLOOP_NOTIFY_DNOTIFY) || defined(IOLOOP_NOTIFY_INOTIFY)

struct io *io_notify_fd_add(struct ioloop_notify_fd_context *ctx, int fd,
			    io_callback_t *callback, void *context)
{
	struct io_notify *io;

	io = i_new(struct io_notify, 1);
	io->io.condition = IO_NOTIFY;
	io->io.callback = callback;
	io->io.context = context;
	io->fd = fd;

	if (ctx->notifies != NULL) {
		ctx->notifies->prev = io;
		io->next = ctx->notifies;
	}
	ctx->notifies = io;
	return &io->io;
}

void io_notify_fd_free(struct ioloop_notify_fd_context *ctx,
		       struct io_notify *io)
{
	if (io->prev != NULL)
		io->prev->next = io->next;
	else
		ctx->notifies = io->next;

	if (io->next != NULL)
		io->next->prev = io->prev;
	i_free(io);
}

struct io_notify *
io_notify_fd_find(struct ioloop_notify_fd_context *ctx, int fd)
{
	struct io_notify *io;

	for (io = ctx->notifies; io != NULL; io = io->next) {
		if (io->fd == fd)
			return io;
	}

	return NULL;
}

#endif

--- NEW FILE: ioloop-notify-fd.h ---
#ifndef __IOLOOP_NOTIFY_FD_H
#define __IOLOOP_NOTIFY_FD_H

/* common notify code for fd-based notifications (dnotify, inotify) */

struct io_notify {
	struct io io;

	/* use a doubly linked list so that io_remove() is quick */
	struct io_notify *prev, *next;

	int fd;
};

struct ioloop_notify_fd_context {
	struct io_notify *notifies;
};

struct io *io_notify_fd_add(struct ioloop_notify_fd_context *ctx, int fd,
			    io_callback_t *callback, void *context);
void io_notify_fd_free(struct ioloop_notify_fd_context *ctx,
		       struct io_notify *io);

struct io_notify *
io_notify_fd_find(struct ioloop_notify_fd_context *ctx, int fd);

#endif

Index: ioloop-notify-inotify.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-inotify.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- ioloop-notify-inotify.c	18 Jan 2007 16:44:09 -0000	1.12
+++ ioloop-notify-inotify.c	8 Mar 2007 22:04:21 -0000	1.13
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Johannes Berg */
+/* Copyright (C) 2005-2007 Johannes Berg, Timo Sirainen */
 
 #define _GNU_SOURCE
 #include "lib.h"
@@ -7,6 +7,7 @@
 
 #include "fd-close-on-exec.h"
 #include "ioloop-internal.h"
+#include "ioloop-notify-fd.h"
 #include "buffer.h"
 #include "network.h"
 
@@ -16,136 +17,115 @@
 #include <sys/ioctl.h>
 #include <sys/inotify.h>
 
-#define INITIAL_INOTIFY_BUFLEN (FILENAME_MAX + sizeof(struct inotify_event))
-#define MAXIMAL_INOTIFY_BUFLEN (32*1024)
-
-struct inotify_io {
-	struct io io;
-	int wd;
-};
+#define INOTIFY_BUFLEN (32*1024)
 
 struct ioloop_notify_handler_context {
-	int inotify_fd;
+	struct ioloop_notify_fd_context fd_ctx;
 
+	int inotify_fd;
 	struct io *event_io;
 
-	buffer_t *buf;
 	bool disabled;
 };
 
-static bool event_read_next(struct ioloop *ioloop)
+static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void);
+
+static bool inotify_input_more(struct ioloop *ioloop)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct io *io;
-        struct inotify_event *event;
-	ssize_t ret;
-	size_t record_length;
-	int required_bytes;
-
-	if (ioctl(ctx->inotify_fd, FIONREAD, &required_bytes))
-		i_fatal("ioctl(inotify_fd, FIONREAD) failed: %m");
-
-	if (required_bytes <= 0)
-		return FALSE;
-
-	if (required_bytes > MAXIMAL_INOTIFY_BUFLEN)
-		required_bytes = MAXIMAL_INOTIFY_BUFLEN;
-
-	event = buffer_get_space_unsafe(ctx->buf, 0, required_bytes);
-	ret = read(ctx->inotify_fd, (void *)event, required_bytes);
-
-	if (ret == 0)
-		return FALSE;
+        const struct inotify_event *event;
+	unsigned char event_buf[INOTIFY_BUFLEN];
+	struct io_notify *io;
+	ssize_t ret, pos;
 
-	if (ret < 0)
-		i_fatal("read(inotify_fd) failed: %m");
+	/* read as many events as there is available and fit into our buffer.
+	   only full events are returned by the kernel. */
+	ret = read(ctx->inotify_fd, event_buf, sizeof(event_buf));
+	if (ret <= 0) {
+		if (ret == 0) {
+			/* nothing more to read */
+			return FALSE;
+		}
+		i_fatal("read(inotify) failed: %m");
+	}
 
 	if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
 		i_fatal("gettimeofday(): %m");
 	ioloop_time = ioloop_timeval.tv_sec;
 
-	while ((size_t)required_bytes > sizeof(*event)) {
-		for (io = ioloop->notifys; io != NULL; io = io->next) {
-			struct inotify_io *iio = (struct inotify_io *)io;
-
-			if (iio->wd == event->wd) {
-				io->callback(io->context);
-				break;
-			}
-		}
-
-		record_length = event->len + sizeof(struct inotify_event);
-		if ((size_t)required_bytes < record_length)
+	for (pos = 0; pos < ret; ) {
+		if ((size_t)(ret - pos) < sizeof(*event))
 			break;
-		required_bytes -= record_length;
 
-		/* this might point outside the area if the loop
-		   won't run again */
-		event = PTR_OFFSET(event, record_length);
-	}
+		event = (struct inotify_event *)(event_buf + pos);
+		pos += sizeof(*event) + event->len;
 
+		io = io_notify_fd_find(&ctx->fd_ctx, event->wd);
+		if (io != NULL)
+			io->io.callback(io->io.context);
+	}
+	if (pos != ret)
+		i_error("read(inotify) returned partial event");
 	return TRUE;
 }
 
-static void event_callback(struct ioloop *ioloop)
+static void inotify_input(struct ioloop *ioloop)
 {
-	while (event_read_next(ioloop)) ;
+	while (inotify_input_more(ioloop)) ;
 }
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
-			      io_callback_t *callback, void *context)
+#undef io_add_notify
+struct io *io_add_notify(const char *path, io_callback_t *callback,
+			 void *context)
 {
 	struct ioloop_notify_handler_context *ctx =
-		ioloop->notify_handler_context;
-	struct inotify_io *io;
-	int watchdescriptor;
+		current_ioloop->notify_handler_context;
+	int fd;
 
+	if (ctx == NULL)
+		ctx = io_loop_notify_handler_init();
 	if (ctx->disabled)
 		return NULL;
 
-	watchdescriptor = inotify_add_watch(ctx->inotify_fd, path,
-					    IN_CREATE | IN_DELETE | IN_MOVE |
-					    IN_CLOSE | IN_MODIFY);
-	
-	if (watchdescriptor < 0) {
-		ctx->disabled = TRUE;
+	fd = inotify_add_watch(ctx->inotify_fd, path,
+			       IN_CREATE | IN_DELETE | IN_MOVE |
+			       IN_CLOSE | IN_MODIFY);
+	if (fd < 0) {
 		/* ESTALE could happen with NFS. Don't bother giving an error
 		   message then. */
 		if (errno != ESTALE)
 			i_error("inotify_add_watch(%s) failed: %m", path);
+		ctx->disabled = TRUE;
 		return NULL;
 	}
 
 	if (ctx->event_io == NULL) {
 		ctx->event_io = io_add(ctx->inotify_fd, IO_READ,
-				       event_callback, ioloop);
+				       inotify_input, current_ioloop);
 	}
 
-	io = p_new(ioloop->pool, struct inotify_io, 1);
-	io->io.fd = -1;
-
-	io->io.callback = callback;
-	io->io.context = context;
-	io->wd = watchdescriptor;
-	return &io->io;
+	return io_notify_fd_add(&ctx->fd_ctx, fd, callback, context);
 }
 
 void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct inotify_io *io = (struct inotify_io *)_io;
+	struct io_notify *io = (struct io_notify *)_io;
 
-	if (inotify_rm_watch(ctx->inotify_fd, io->wd) < 0)
+	if (inotify_rm_watch(ctx->inotify_fd, io->fd) < 0)
 		i_error("inotify_rm_watch() failed: %m");
 
-	if (ioloop->notifys == NULL)
+	io_notify_fd_free(&ctx->fd_ctx, io);
+
+	if (ctx->fd_ctx.notifies == NULL)
 		io_remove(&ctx->event_io);
 }
 
-void io_loop_notify_handler_init(struct ioloop *ioloop)
+static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void)
 {
+	struct ioloop *ioloop = current_ioloop;
 	struct ioloop_notify_handler_context *ctx;
 
 	ctx = ioloop->notify_handler_context =
@@ -155,11 +135,10 @@
 	if (ctx->inotify_fd == -1) {
 		i_error("inotify_init() failed: %m");
 		ctx->disabled = TRUE;
-		return;
+	} else {
+		fd_close_on_exec(ctx->inotify_fd, TRUE);
 	}
-	fd_close_on_exec(ctx->inotify_fd, TRUE);
-
-	ctx->buf = buffer_create_dynamic(default_pool, INITIAL_INOTIFY_BUFLEN);
+	return ctx;
 }
 
 void io_loop_notify_handler_deinit(struct ioloop *ioloop)
@@ -167,12 +146,10 @@
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
 
-	if (ctx->inotify_fd != -1)
+	if (ctx->inotify_fd != -1) {
 		if (close(ctx->inotify_fd) < 0)
-			i_error("close(inotify descriptor) failed: %m");
-
-	if (ctx->buf != NULL)
-		buffer_free(ctx->buf);
+			i_error("close(inotify) failed: %m");
+	}
 	i_free(ctx);
 }
 

Index: ioloop-notify-kqueue.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-kqueue.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- ioloop-notify-kqueue.c	15 Dec 2006 18:38:10 -0000	1.8
+++ ioloop-notify-kqueue.c	8 Mar 2007 22:04:21 -0000	1.9
@@ -33,6 +33,12 @@
 	EV_SET(a, b, c, d, e, f, g)
 #endif
 
+struct io_notify {
+	struct io io;
+	int refcount;
+	int fd;
+};
+
 struct ioloop_notify_handler_context {
 	int kq;
 	struct io *event_io;
@@ -40,39 +46,55 @@
 
 static void event_callback(struct ioloop_notify_handler_context *ctx)
 {
-	struct io *io;
-	struct kevent ev;
+	struct io_notify *io;
+	struct kevent events[64];
 	struct timespec ts;
-	int ret;
-
-	if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
-		i_fatal("gettimeofday() failed: %m");
-	ioloop_time = ioloop_timeval.tv_sec;
+	int i, ret;
 
 	ts.tv_sec = 0;
 	ts.tv_nsec = 0;
 
-	ret = kevent(ctx->kq, NULL, 0, &ev, 1, &ts);
+	ret = kevent(ctx->kq, NULL, 0, events,
+		     sizeof(events)/sizeof(events[0]), &ts);
 	if (ret <= 0) {
 		if (ret == 0 || errno == EINTR)
 			return;
 
 		i_fatal("kevent(notify) failed: %m");
 	}
-	io = (void *)ev.udata;
-	io->callback(io->context);
+
+	if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
+		i_fatal("gettimeofday() failed: %m");
+	ioloop_time = ioloop_timeval.tv_sec;
+
+	for (i = 0; i < ret; i++) {
+		io = (void *)events[i].udata;
+		i_assert(io->refcount == 1);
+		io->refcount++;
+	}
+	for (i = 0; i < ret; i++) {
+		io = (void *)events[i].udata;
+		/* there can be multiple events for a single io.
+		   call the callback only once if that happens. */
+		if (io->refcount == 2 && io->io.callback != NULL)
+			io->io.callback(io->io.context);
+
+		if (--io->refcount == 0)
+			i_free(io);
+	}
 }
 
-void io_loop_notify_handler_init(struct ioloop *ioloop)
+static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void)
 {
 	struct ioloop_notify_handler_context *ctx;
 
-	ctx = ioloop->notify_handler_context =
-		p_new(ioloop->pool, struct ioloop_notify_handler_context, 1);
+	ctx = current_ioloop->notify_handler_context =
+		i_new(struct ioloop_notify_handler_context, 1);
 	ctx->kq = kqueue();
 	if (ctx->kq < 0)
 		i_fatal("kqueue(notify) failed: %m");
 	fd_close_on_exec(ctx->kq, TRUE);
+	return ctx;
 }
 
 void io_loop_notify_handler_deinit(struct ioloop *ioloop)
@@ -84,19 +106,23 @@
 		io_remove(&ctx->event_io);
 	if (close(ctx->kq) < 0)
 		i_error("close(kqueue notify) failed: %m");
-	p_free(ioloop->pool, ctx);
+	i_free(ctx);
 }
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
-			      io_callback_t *callback, void *context)
+#undef io_add_notify
+struct io *io_add_notify(const char *path, io_callback_t *callback,
+			 void *context)
 {
 	struct ioloop_notify_handler_context *ctx =
-		ioloop->notify_handler_context;
+		current_ioloop->notify_handler_context;
 	struct kevent ev;
-	struct io *io;
+	struct io_notify *io;
 	int fd;
 	struct stat sb;
 
+	if (ctx == NULL)
+		ctx = io_loop_notify_handler_init();
+
 	fd = open(path, O_RDONLY);
 	if (fd == -1) {
 		if (errno != ENOENT)
@@ -115,10 +141,11 @@
 	}
 	fd_close_on_exec(fd, TRUE);
 
-	io = p_new(ioloop->pool, struct io, 1);
+	io = i_new(struct io_notify, 1);
+	io->io.callback = callback;
+	io->io.context = context;
+	io->refcount = 1;
 	io->fd = fd;
-	io->callback = callback;
-	io->context = context;
 
 	/* EV_CLEAR flag is needed because the EVFILT_VNODE filter reports
 	   event state transitions and not the current state.  With this flag,
@@ -128,31 +155,33 @@
 	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);
+		i_free(io);
 		return NULL;
 	}
 
 	if (ctx->event_io == NULL) {
-		ctx->event_io =
-			io_add(ctx->kq, IO_READ, event_callback,
-			       ioloop->notify_handler_context);
+		ctx->event_io = io_add(ctx->kq, IO_READ, event_callback,
+				       current_ioloop->notify_handler_context);
 	}
-	return io;
+	return &io->io;
 }
 
-void io_loop_notify_remove(struct ioloop *ioloop, struct io *io)
+void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
+	struct io_notify *io = (struct io_notify *)_io;
 	struct kevent ev;
 
-	i_assert((io->condition & IO_NOTIFY) != 0);
-
 	MY_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) for notify remove failed: %m", io->fd);
+	io->fd = -1;
+
+	if (--io->refcount == 0)
+		i_free(io);
 }
 
 #endif

Index: ioloop-poll.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-poll.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- ioloop-poll.c	28 Dec 2006 18:09:07 -0000	1.34
+++ ioloop-poll.c	8 Mar 2007 22:04:21 -0000	1.35
@@ -22,31 +22,30 @@
 {
 	struct ioloop_handler_context *ctx;
 
-	ioloop->handler_context = ctx =
-		p_new(ioloop->pool, struct ioloop_handler_context, 1);
+	ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
 	ctx->fds_count = IOLOOP_INITIAL_FD_COUNT;
-	ctx->fds = p_new(ioloop->pool, struct pollfd, ctx->fds_count);
+	ctx->fds = i_new(struct pollfd, ctx->fds_count);
 
 	ctx->idx_count = IOLOOP_INITIAL_FD_COUNT;
-	ctx->fd_index = p_new(ioloop->pool, int, ctx->idx_count);
+	ctx->fd_index = i_new(int, ctx->idx_count);
         memset(ctx->fd_index, 0xff, sizeof(int) * ctx->idx_count);
 }
 
 void io_loop_handler_deinit(struct ioloop *ioloop)
 {
-        p_free(ioloop->pool, ioloop->handler_context->fds);
-        p_free(ioloop->pool, ioloop->handler_context->fd_index);
-        p_free(ioloop->pool, ioloop->handler_context);
+        i_free(ioloop->handler_context->fds);
+        i_free(ioloop->handler_context->fd_index);
+        i_free(ioloop->handler_context);
 }
 
 #define IO_POLL_ERROR (POLLERR | POLLHUP | POLLNVAL)
 #define IO_POLL_INPUT (POLLIN | POLLPRI | IO_POLL_ERROR)
 #define IO_POLL_OUTPUT (POLLOUT | IO_POLL_ERROR)
 
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	enum io_condition condition = io->condition;
+	enum io_condition condition = io->io.condition;
 	unsigned int old_count;
 	int index, fd = io->fd;
 
@@ -56,7 +55,7 @@
 
 		ctx->idx_count = nearest_power((unsigned int) fd+1);
 
-		ctx->fd_index = p_realloc(ioloop->pool, ctx->fd_index,
+		ctx->fd_index = i_realloc(ctx->fd_index,
 					  sizeof(int) * old_count,
 					  sizeof(int) * ctx->idx_count);
 		memset(ctx->fd_index + old_count, 0xff,
@@ -69,7 +68,7 @@
 
 		ctx->fds_count = nearest_power(ctx->fds_count+1);
 
-		ctx->fds = p_realloc(ioloop->pool, ctx->fds,
+		ctx->fds = i_realloc(ctx->fds,
 				     sizeof(struct pollfd) * old_count,
 				     sizeof(struct pollfd) * ctx->fds_count);
 	}
@@ -95,10 +94,10 @@
 		ctx->fds[index].events |= IO_POLL_ERROR;
 }
 
-void io_loop_handle_remove(struct ioloop *ioloop,  struct io *io)
+void io_loop_handle_remove(struct ioloop *ioloop,  struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	enum io_condition condition = io->condition;
+	enum io_condition condition = io->io.condition;
 	int index, fd = io->fd;
 
 	index = ctx->fd_index[fd];
@@ -116,6 +115,7 @@
 			i_error("fcntl(%d, F_GETFD) failed: %m", io->fd);
 	}
 #endif
+	i_free(io);
 
 	if (condition & IO_READ) {
 		ctx->fds[index].events &= ~(POLLIN|POLLPRI);
@@ -143,7 +143,7 @@
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
         struct pollfd *pollfd;
         struct timeval tv;
-	struct io *io;
+	struct io_file *io;
 	unsigned int t_id;
 	int msecs, ret;
 	bool call;
@@ -163,28 +163,29 @@
 		return;
 	}
 
-	for (io = ioloop->ios; io != NULL && ret > 0; io = ioloop->next_io) {
-		ioloop->next_io = io->next;
+	io = ioloop->io_files;
+	for (; io != NULL && ret > 0; io = ioloop->next_io_file) {
+		ioloop->next_io_file = io->next;
 
 		pollfd = &ctx->fds[ctx->fd_index[io->fd]];
 		if (pollfd->revents != 0) {
 			if (pollfd->revents & POLLNVAL) {
 				i_error("invalid I/O fd %d, callback %p",
-					io->fd, (void *) io->callback);
+					io->fd, (void *) io->io.callback);
 				pollfd->events = 0;
 				pollfd->revents = 0;
 				call = TRUE;
-			} else if ((io->condition &
+			} else if ((io->io.condition &
 				    (IO_READ|IO_WRITE)) == (IO_READ|IO_WRITE)) {
 				call = TRUE;
 				pollfd->revents = 0;
-			} else if (io->condition & IO_READ) {
+			} else if (io->io.condition & IO_READ) {
 				call = (pollfd->revents & IO_POLL_INPUT) != 0;
 				pollfd->revents &= ~IO_POLL_INPUT;
-			} else if (io->condition & IO_WRITE) {
+			} else if (io->io.condition & IO_WRITE) {
 				call = (pollfd->revents & IO_POLL_OUTPUT) != 0;
 				pollfd->revents &= ~IO_POLL_OUTPUT;
-			} else if (io->condition & IO_ERROR) {
+			} else if (io->io.condition & IO_ERROR) {
 				call = (pollfd->revents & IO_POLL_ERROR) != 0;
 				pollfd->revents &= ~IO_POLL_ERROR;
 			} else {
@@ -196,11 +197,11 @@
 
 			if (call) {
 				t_id = t_push();
-				io->callback(io->context);
+				io->io.callback(io->io.context);
 				if (t_pop() != t_id) {
 					i_panic("Leaked a t_pop() call in "
 						"I/O handler %p",
-						(void *)io->callback);
+						(void *)io->io.callback);
 				}
 			}
 		}

Index: ioloop-select.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-select.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- ioloop-select.c	7 Mar 2007 15:57:41 -0000	1.24
+++ ioloop-select.c	8 Mar 2007 22:04:21 -0000	1.25
@@ -20,13 +20,13 @@
 static void update_highest_fd(struct ioloop *ioloop)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-        struct io *io;
+        struct io_file *io;
 	int max_highest_fd;
 
         max_highest_fd = ctx->highest_fd-1;
 	ctx->highest_fd = -1;
 
-	for (io = ioloop->ios; io != NULL; io = io->next) {
+	for (io = ioloop->io_files; io != NULL; io = io->next) {
 		if (io->fd <= ctx->highest_fd)
 			continue;
 
@@ -41,8 +41,7 @@
 {
 	struct ioloop_handler_context *ctx;
 
-	ioloop->handler_context = ctx =
-		p_new(ioloop->pool, struct ioloop_handler_context, 1);
+	ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
 	ctx->highest_fd = -1;
         FD_ZERO(&ctx->read_fds);
 	FD_ZERO(&ctx->write_fds);
@@ -51,13 +50,13 @@
 
 void io_loop_handler_deinit(struct ioloop *ioloop)
 {
-        p_free(ioloop->pool, ioloop->handler_context);
+        i_free(ioloop->handler_context);
 }
 
-void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_add(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	enum io_condition condition = io->condition;
+	enum io_condition condition = io->io.condition;
 	int fd = io->fd;
 
 	i_assert(fd >= 0);
@@ -75,10 +74,10 @@
 		ctx->highest_fd = io->fd;
 }
 
-void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
+void io_loop_handle_remove(struct ioloop *ioloop, struct io_file *io)
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
-	enum io_condition condition = io->condition;
+	enum io_condition condition = io->io.condition;
 	int fd = io->fd;
 
 	i_assert(fd >= 0 && fd < FD_SETSIZE);
@@ -95,6 +94,7 @@
 		if (io->fd == ctx->highest_fd)
 			update_highest_fd(ioloop);
 	}
+	i_free(io);
 }
 
 #define io_check_condition(ctx, fd, cond) \
@@ -106,7 +106,7 @@
 {
 	struct ioloop_handler_context *ctx = ioloop->handler_context;
 	struct timeval tv;
-	struct io *io;
+	struct io_file *io;
 	unsigned int t_id;
 	int ret;
 
@@ -130,17 +130,19 @@
 		return;
 	}
 
-	for (io = ioloop->ios; io != NULL && ret > 0; io = ioloop->next_io) {
-                ioloop->next_io = io->next;
+	io = ioloop->io_files;
+	for (; io != NULL && ret > 0; io = ioloop->next_io_file) {
+                ioloop->next_io_file = io->next;
 
-		if (io_check_condition(ctx, io->fd, io->condition)) {
+		if (io_check_condition(ctx, io->fd, io->io.condition)) {
 			ret--;
 
 			t_id = t_push();
-			io->callback(io->context);
+			io->io.callback(io->io.context);
 			if (t_pop() != t_id) {
 				i_panic("Leaked a t_pop() call in "
-					"I/O handler %p", (void *)io->callback);
+					"I/O handler %p",
+					(void *)io->io.callback);
 			}
 		}
 	}

Index: ioloop.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- ioloop.c	7 Mar 2007 16:08:02 -0000	1.43
+++ ioloop.c	8 Mar 2007 22:04:21 -0000	1.44
@@ -23,54 +23,43 @@
 struct io *io_add(int fd, enum io_condition condition,
 		  io_callback_t *callback, void *context)
 {
-	struct io *io;
+	struct io_file *io;
 
 	i_assert(fd >= 0);
 	i_assert(callback != NULL);
 	i_assert((condition & IO_NOTIFY) == 0);
 
-	io = p_new(current_ioloop->pool, struct io, 1);
+	io = i_new(struct io_file, 1);
+        io->io.condition = condition;
+	io->io.callback = callback;
+        io->io.context = context;
 	io->refcount = 1;
 	io->fd = fd;
-        io->condition = condition;
-
-	io->callback = callback;
-        io->context = context;
 
 	io_loop_handle_add(current_ioloop, io);
 
-	io->next = current_ioloop->ios;
-	current_ioloop->ios = io;
-
-	if (io->next != NULL)
-		io->next->prev = io;
-	return io;
+	if (current_ioloop->io_files != NULL) {
+		current_ioloop->io_files->prev = io;
+		io->next = current_ioloop->io_files;
+	}
+	current_ioloop->io_files = io;
+	return &io->io;
 }
 
-#undef io_add_notify
-struct io *io_add_notify(const char *path, io_callback_t *callback,
-			 void *context)
+static void io_file_unlink(struct io_file *io)
 {
-	struct io *io;
-
-	i_assert(path != NULL);
-	i_assert(callback != NULL);
-
-	if (current_ioloop->notify_handler_context == NULL)
-		io_loop_notify_handler_init(current_ioloop);
-
-	io = io_loop_notify_add(current_ioloop, path, callback, context);
-	if (io == NULL)
-		return NULL;
-
-	io->refcount = 1;
-	io->condition |= IO_NOTIFY;
-	io->next = current_ioloop->notifys;
-	current_ioloop->notifys = io;
+	if (io->prev != NULL)
+		io->prev->next = io->next;
+	else
+		current_ioloop->io_files = io->next;
 
 	if (io->next != NULL)
-		io->next->prev = io;
-	return io;
+		io->next->prev = io->prev;
+
+	/* if we got here from an I/O handler callback, make sure we
+	   don't try to handle this one next. */
+	if (current_ioloop->next_io_file == io)
+		current_ioloop->next_io_file = io->next;
 }
 
 void io_remove(struct io **_io)
@@ -79,35 +68,18 @@
 
 	*_io = NULL;
 
-	i_assert(io->refcount > 0);
+	/* make sure the callback doesn't get called anymore.
+	   kqueue code relies on this. */
+	io->callback = NULL;
 
-	/* unlink from linked list */
-	if (io->prev != NULL)
-		io->prev->next = io->next;
+	if ((io->condition & IO_NOTIFY) != 0)
+		io_loop_notify_remove(current_ioloop, io);
 	else {
-		if ((io->condition & IO_NOTIFY) == 0)
-			current_ioloop->ios = io->next;
-		else
-			current_ioloop->notifys = io->next;
-	}
-	if (io->next != NULL)
-		io->next->prev = io->prev;
-
-	if ((io->condition & IO_NOTIFY) == 0) {
-		/* if we got here from an I/O handler callback, make sure we
-		   don't try to handle this one next. */
-		if (current_ioloop->next_io == io)
-			current_ioloop->next_io = io->next;
+		struct io_file *io_file = (struct io_file *)io;
 
-		io_loop_handle_remove(current_ioloop, io);
-	} else {
-		io_loop_notify_remove(current_ioloop, io);
+		io_file_unlink(io_file);
+		io_loop_handle_remove(current_ioloop, io_file);
 	}
-
-	io->callback = NULL;
-
-	if (--io->refcount == 0)
-		p_free(current_ioloop->pool, io);
 }
 
 static void timeout_list_insert(struct ioloop *ioloop, struct timeout *timeout)
@@ -154,7 +126,7 @@
 {
 	struct timeout *timeout;
 
-	timeout = p_new(current_ioloop->pool, struct timeout, 1);
+	timeout = i_new(struct timeout, 1);
         timeout->msecs = msecs;
 
 	timeout->callback = callback;
@@ -174,14 +146,6 @@
 	*timeout = NULL;
 }
 
-void timeout_destroy(struct ioloop *ioloop, struct timeout **timeout_p)
-{
-        struct timeout *timeout = *timeout_p;
-
-	*timeout_p = timeout->next;
-        p_free(ioloop->pool, timeout);
-}
-
 int io_loop_get_wait_time(struct timeout *timeout, struct timeval *tv,
 			  struct timeval *tv_now)
 {
@@ -268,7 +232,8 @@
 		struct timeout *t = ioloop->timeouts;
 
 		if (t->destroyed) {
-                        timeout_destroy(ioloop, &ioloop->timeouts);
+			ioloop->timeouts = t->next;
+			i_free(t);
 			continue;
 		}
 
@@ -300,9 +265,10 @@
 	while (called_timeouts != NULL) {
 		struct timeout *t = called_timeouts;
 
-		if (t->destroyed)
-			timeout_destroy(ioloop, &called_timeouts);
-		else {
+		if (t->destroyed) {
+			called_timeouts = t->next;
+			i_free(t);
+		} else {
 			called_timeouts = t->next;
 			timeout_list_insert(current_ioloop, t);
 		}
@@ -341,7 +307,7 @@
         return ioloop->running;
 }
 
-struct ioloop *io_loop_create(pool_t pool)
+struct ioloop *io_loop_create(void)
 {
 	struct ioloop *ioloop;
 
@@ -350,10 +316,7 @@
 		i_fatal("gettimeofday(): %m");
 	ioloop_time = ioloop_timeval.tv_sec;
 
-        ioloop = p_new(pool, struct ioloop, 1);
-	pool_ref(pool);
-	ioloop->pool = pool;
-
+        ioloop = i_new(struct ioloop, 1);
 	io_loop_handler_init(ioloop);
 
 	ioloop->prev = current_ioloop;
@@ -365,18 +328,18 @@
 void io_loop_destroy(struct ioloop **_ioloop)
 {
         struct ioloop *ioloop = *_ioloop;
-	pool_t pool;
 
 	*_ioloop = NULL;
 
 	if (ioloop->notify_handler_context != NULL)
 		io_loop_notify_handler_deinit(ioloop);
 
-	while (ioloop->ios != NULL) {
-		struct io *io = ioloop->ios;
+	while (ioloop->io_files != NULL) {
+		struct io_file *io = ioloop->io_files;
+		struct io *_io = &io->io;
 
-		i_warning("I/O leak: %p (%d)", (void *)io->callback, io->fd);
-		io_remove(&io);
+		i_warning("I/O leak: %p (%d)", (void *)io->io.callback, io->fd);
+		io_remove(&_io);
 	}
 
 	while (ioloop->timeouts != NULL) {
@@ -386,7 +349,8 @@
 			i_warning("Timeout leak: %p", (void *)to->callback);
 			timeout_remove(&to);
 		}
-                timeout_destroy(ioloop, &ioloop->timeouts);
+		ioloop->timeouts = to->next;
+		i_free(to);
 	}
 	
         io_loop_handler_deinit(ioloop);
@@ -395,7 +359,5 @@
         i_assert(ioloop == current_ioloop);
 	current_ioloop = current_ioloop->prev;
 
-	pool = ioloop->pool;
-	p_free(pool, ioloop);
-	pool_unref(pool);
+	i_free(ioloop);
 }

Index: ioloop.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- ioloop.h	15 Dec 2006 16:55:32 -0000	1.20
+++ ioloop.h	8 Mar 2007 22:04:21 -0000	1.21
@@ -65,7 +65,7 @@
 void io_loop_set_running(struct ioloop *ioloop);
 void io_loop_handler_run(struct ioloop *ioloop);
 
-struct ioloop *io_loop_create(pool_t pool);
+struct ioloop *io_loop_create(void);
 /* Destroy I/O loop and set ioloop pointer to NULL. */
 void io_loop_destroy(struct ioloop **ioloop);
 



More information about the dovecot-cvs mailing list