diff -urpNX /usr/share/dontdiff dovecot-cvs.vanilla/configure.in dovecot-cvs/configure.in --- dovecot-cvs.vanilla/configure.in 2004-08-09 23:14:02.000000000 +0400 +++ dovecot-cvs/configure.in 2004-08-25 19:37:47.000000000 +0400 @@ -265,10 +265,14 @@ AC_CHECK_FUNCS(fcntl flock lockf inet_at dnl * poll/select? -AC_CHECK_FUNC(poll, [ - AC_DEFINE(IOLOOP_POLL,, Implement I/O loop with poll()) -], [ - AC_DEFINE(IOLOOP_SELECT,, Implement I/O loop with select()) +AC_CHECK_FUNC(epoll_create, [ + AC_DEFINE(IOLOOP_EPOLL,, Implement I/O loop with Linux 2.6 epoll()) + ], [ + AC_CHECK_FUNC(poll, [ + AC_DEFINE(IOLOOP_POLL,, Implement I/O loop with poll()) + ], [ + AC_DEFINE(IOLOOP_SELECT,, Implement I/O loop with select()) + ]) ]) dnl * dnotify? diff -urpNX /usr/share/dontdiff dovecot-cvs.vanilla/src/lib/ioloop-epoll.c dovecot-cvs/src/lib/ioloop-epoll.c --- dovecot-cvs.vanilla/src/lib/ioloop-epoll.c 1970-01-01 03:00:00.000000000 +0300 +++ dovecot-cvs/src/lib/ioloop-epoll.c 2004-08-29 16:59:22.000000000 +0400 @@ -0,0 +1,248 @@ +/* + * Linux epoll() based ioloop handler. + * + * Copyright (c) 2004 Andrey Panin + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* @UNSAFE: whole file */ + +#include "lib.h" +#include "ioloop-internal.h" + +#ifdef IOLOOP_EPOLL + +#include +#include + +#define INITIAL_EPOLL_EVENTS 128 +#define EPOLL_IOS_PER_FD 2 + +struct ioloop_handler_data { + int epfd; + int events_size, events_pos; + struct epoll_event *events; + + unsigned int idx_size; + struct io_list **fd_index; +}; + +struct io_list { + int count; + struct io *ios[EPOLL_IOS_PER_FD]; +}; + +void io_loop_handler_init(struct ioloop *ioloop) +{ + struct ioloop_handler_data *data; + + ioloop->handler_data = data = + p_new(ioloop->pool, struct ioloop_handler_data, 1); + + data->events_pos = 0; + data->events_size = INITIAL_EPOLL_EVENTS; + data->events = p_new(ioloop->pool, struct epoll_event, + data->events_size); + + data->idx_size = INITIAL_EPOLL_EVENTS; + data->fd_index = p_new(ioloop->pool, struct io_list *, data->idx_size); + + data->epfd = epoll_create(INITIAL_EPOLL_EVENTS); +} + +void io_loop_handler_deinit(struct ioloop *ioloop) +{ + struct ioloop_handler_data *data = ioloop->handler_data; + + close(data->epfd); + p_free(ioloop->pool, ioloop->handler_data->events); + p_free(ioloop->pool, ioloop->handler_data->fd_index); + p_free(ioloop->pool, ioloop->handler_data); +} + +#define IO_EPOLL_INPUT (EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP) +#define IO_EPOLL_OUTPUT (EPOLLOUT | EPOLLERR | EPOLLHUP) + +static int epoll_event_mask(struct io_list *list) +{ + int events = 0, i; + struct io *io; + + for (i = 0; i < list->count; i++) { + io = list->ios[i]; + + if (!io) + continue; + + if (io->condition & IO_READ) + events |= IO_EPOLL_INPUT; + if (io->condition & IO_WRITE) + events |= IO_EPOLL_OUTPUT; + } + + return events; +} + +static void iolist_add(struct io_list *list, struct io *io) +{ + int i; + + i_assert(list->count < EPOLL_IOS_PER_FD); + + for (i = 0; i < EPOLL_IOS_PER_FD; i++) { + if (!list->ios[i]) { + list->ios[i] = io; + break; + } + } + + list->count++; +} + +static void iolist_del(struct io_list *list, struct io *io) +{ + int i; + + for (i = 0; i < EPOLL_IOS_PER_FD; i++) { + if (list->ios[i] == io) { + list->ios[i] = NULL; + break; + } + } + + list->count--; +} + +void io_loop_handle_add(struct ioloop *ioloop, struct io *io) +{ + struct ioloop_handler_data *data = ioloop->handler_data; + int ret, op, fd = io->fd; + struct io_list *list = data->fd_index[fd]; + struct epoll_event event; + + if (!list) { + if ((unsigned int) fd >= data->idx_size) { + /* grow the fd -> iolist array */ + unsigned int old_size = data->idx_size; + + data->idx_size = nearest_power((unsigned int) fd+1); + + i_assert(data->idx_size < (size_t)-1 / sizeof(int)); + + data->fd_index = p_realloc(ioloop->pool, data->fd_index, + sizeof(int) * old_size, + sizeof(int) * data->idx_size); + } + + data->fd_index[fd] = list = + p_new(ioloop->pool, struct io_list, 1); + } + + iolist_add(list, io); + + event.data.ptr = list; + event.events = epoll_event_mask(list); + + op = (list->count == 1) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; + + ret = epoll_ctl(data->epfd, op, fd, &event); + if (ret < 0) + i_warning("epoll_ctl() : %m"); + + if (data->events_pos >= data->events_size) { + data->events_size = nearest_power(data->events_size + 1); + + p_free(ioloop->pool, data->events); + data->events = p_new(ioloop->pool, struct epoll_event, + data->events_size); + } + + data->events_pos++; +} + +void io_loop_handle_remove(struct ioloop *ioloop, struct io *io) +{ + struct ioloop_handler_data *data = ioloop->handler_data; + struct io_list *list = data->fd_index[io->fd]; + struct epoll_event event; + int ret, op; + + i_assert(list); + i_assert(list->count > 0); + + iolist_del(list, io); + + event.data.ptr = list; + event.events = epoll_event_mask(list); + + op = (list->count == 0) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; + + ret = epoll_ctl(data->epfd, op, io->fd, &event); + if ((ret < 0) && (errno != EBADF)) + i_warning("epoll_ctl() : %m"); + + data->events_pos--; +} + +#define IO_RW (IO_READ | IO_WRITE) + +void io_loop_handler_run(struct ioloop *ioloop) +{ + struct ioloop_handler_data *data = ioloop->handler_data; + struct epoll_event *event; + struct io_list *list; + struct io *io; + struct timeval tv; + unsigned int t_id; + int msecs, ret, i, call; + + /* get the time left for next timeout task */ + msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL); + + ret = epoll_wait(data->epfd, data->events, data->events_size, msecs); + if (ret < 0 && errno != EINTR) + i_warning("epoll_wait() : %m"); + + /* execute timeout handlers */ + io_loop_handle_timeouts(ioloop); + + if (ret <= 0 || !ioloop->running) { + /* No events */ + return; + } + + event = data->events; + while (ret--) { + list = event->data.ptr; + + for (i = 0; i < list->count; i++) { + call = FALSE; + io = list->ios[i]; + + if (event->events & (EPOLLHUP | EPOLLERR)) { + /* FIXME: is this Right Thing to do ? */ + call = TRUE; + } else if ((io->condition & IO_RW) == IO_RW) { + call = TRUE; + } else if (io->condition & IO_READ) { + call = event->events & EPOLLIN; + } else if (io->condition & IO_WRITE) { + call = event->events & EPOLLOUT; + } + + if (call) { + t_id = t_push(); + io->callback(io->context); + if (t_pop() != t_id) + i_panic("Leaked a t_pop() call!"); + } + } + event++; + } +} + +#endif /* IOLOOP_EPOLL */ diff -urpNX /usr/share/dontdiff dovecot-cvs.vanilla/src/lib/Makefile.am dovecot-cvs/src/lib/Makefile.am --- dovecot-cvs.vanilla/src/lib/Makefile.am 2004-08-25 11:11:12.000000000 +0400 +++ dovecot-cvs/src/lib/Makefile.am 2004-08-25 19:35:19.000000000 +0400 @@ -30,6 +30,7 @@ liblib_a_SOURCES = \ ioloop-notify-dn.c \ ioloop-poll.c \ ioloop-select.c \ + ioloop-epoll.c \ lib.c \ lib-signals.c \ md4.c \