# HG changeset patch # User Timo Sirainen # Date 1173391461 -7200 # Node ID 12ac5f685814335af1bbea0fcf83282bf1e5fea4 # Parent c1ef15c1a1faa47137d7df8a3a8e463e3a5fba0b Various cleanups to ioloop code. diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/Makefile.am --- a/src/lib/Makefile.am Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/Makefile.am Fri Mar 09 00:04:21 2007 +0200 @@ -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 \ diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-epoll.c --- a/src/lib/ioloop-epoll.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-epoll.c Fri Mar 09 00:04:21 2007 +0200 @@ -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); } } } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-internal.h --- a/src/lib/ioloop-internal.h Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-internal.h Fri Mar 09 00:04:21 2007 +0200 @@ -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_remove(struct ioloop *ioloop, struct io *io); 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); - #endif diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-iolist.c --- a/src/lib/ioloop-iolist.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-iolist.c Fri Mar 09 00:04:21 2007 +0200 @@ -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; diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-iolist.h --- a/src/lib/ioloop-iolist.h Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-iolist.h Fri Mar 09 00:04:21 2007 +0200 @@ -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 diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-kqueue.c --- a/src/lib/ioloop-kqueue.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-kqueue.c Fri Mar 09 00:04:21 2007 +0200 @@ -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); } } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-notify-dn.c --- a/src/lib/ioloop-notify-dn.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-notify-dn.c Fri Mar 09 00:04:21 2007 +0200 @@ -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 struct ioloop_notify_handler_context { + struct ioloop_notify_fd_context fd_ctx; + struct io *event_io; + int event_pipe[2]; + bool disabled; - - int event_pipe[2]; }; 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; diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-notify-fd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ioloop-notify-fd.c Fri Mar 09 00:04:21 2007 +0200 @@ -0,0 +1,54 @@ +/* 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 diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-notify-fd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ioloop-notify-fd.h Fri Mar 09 00:04:21 2007 +0200 @@ -0,0 +1,27 @@ +#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 diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-notify-inotify.c --- a/src/lib/ioloop-notify-inotify.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-notify-inotify.c Fri Mar 09 00:04:21 2007 +0200 @@ -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 #include -#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 { + 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; + const struct inotify_event *event; + unsigned char event_buf[INOTIFY_BUFLEN]; + struct io_notify *io; + ssize_t ret, pos; - 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; - - 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; + for (pos = 0; pos < ret; ) { + if ((size_t)(ret - pos) < sizeof(*event)) + break; - if (iio->wd == event->wd) { - io->callback(io->context); - break; - } - } + event = (struct inotify_event *)(event_buf + pos); + pos += sizeof(*event) + event->len; - record_length = event->len + sizeof(struct inotify_event); - if ((size_t)required_bytes < record_length) - break; - required_bytes -= record_length; - - /* this might point outside the area if the loop - won't run again */ - event = PTR_OFFSET(event, record_length); + 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); } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-notify-kqueue.c --- a/src/lib/ioloop-notify-kqueue.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-notify-kqueue.c Fri Mar 09 00:04:21 2007 +0200 @@ -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 diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-poll.c --- a/src/lib/ioloop-poll.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-poll.c Fri Mar 09 00:04:21 2007 +0200 @@ -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); } } } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop-select.c --- a/src/lib/ioloop-select.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop-select.c Fri Mar 09 00:04:21 2007 +0200 @@ -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); } } } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop.c --- a/src/lib/ioloop.c Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop.c Fri Mar 09 00:04:21 2007 +0200 @@ -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); - - /* unlink from linked list */ - if (io->prev != NULL) - io->prev->next = io->next; - 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; - - io_loop_handle_remove(current_ioloop, io); - } else { - io_loop_notify_remove(current_ioloop, io); - } - + /* make sure the callback doesn't get called anymore. + kqueue code relies on this. */ io->callback = NULL; - if (--io->refcount == 0) - p_free(current_ioloop->pool, io); + if ((io->condition & IO_NOTIFY) != 0) + io_loop_notify_remove(current_ioloop, io); + else { + struct io_file *io_file = (struct io_file *)io; + + io_file_unlink(io_file); + io_loop_handle_remove(current_ioloop, io_file); + } } 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); } diff -r c1ef15c1a1fa -r 12ac5f685814 src/lib/ioloop.h --- a/src/lib/ioloop.h Thu Mar 08 22:02:36 2007 +0200 +++ b/src/lib/ioloop.h Fri Mar 09 00:04:21 2007 +0200 @@ -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);