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