[dovecot-cvs] dovecot/src/lib Makefile.am, 1.55, 1.56 ioloop-kqueue.c, NONE, 1.1

cras at dovecot.org cras at dovecot.org
Wed Dec 14 20:51:54 EET 2005


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

Modified Files:
	Makefile.am 
Added Files:
	ioloop-kqueue.c 
Log Message:
Added kqueue support. Patch by Vaclav Haisman.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- Makefile.am	25 Nov 2005 15:19:49 -0000	1.55
+++ Makefile.am	14 Dec 2005 18:51:52 -0000	1.56
@@ -35,6 +35,7 @@
 	ioloop-poll.c \
 	ioloop-select.c \
 	ioloop-epoll.c \
+	ioloop-kqueue.c \
 	lib.c \
 	lib-signals.c \
 	md4.c \

--- NEW FILE: ioloop-kqueue.c ---
/*
 * FreeBSD kqueue() based ioloop handler.
 *
 * Copyright (c) 2005 Vaclav Haisman <v.haisman at sh.cvut.cz>
 *
 * 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_KQUEUE

#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

#ifndef INITIAL_BUF_SIZE
#  define INITIAL_BUF_SIZE 128
#endif

struct ioloop_handler_context {
        int kq;
        size_t evbuf_size;
        struct kevent *evbuf;

        size_t fds_size;
        struct fdrecord *fds;
};

struct fdrecord {
        struct io *errio;
        enum io_condition mode;
};

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);

	ctx->evbuf_size = INITIAL_BUF_SIZE;
        ctx->evbuf = p_new(ioloop->pool, struct kevent, ctx->evbuf_size);
        ctx->kq = kqueue();
        if (ctx->kq < 0)
                i_fatal("kqueue(): %m");

        ctx->fds_size = INITIAL_BUF_SIZE;
        ctx->fds = p_new(ioloop->pool, struct fdrecord, ctx->fds_size);
}

void io_loop_handler_deinit(struct ioloop *ioloop)
{
        p_free(ioloop->pool, ioloop->handler_context->evbuf);
        p_free(ioloop->pool, ioloop->handler_context->fds);
        p_free(ioloop->pool, ioloop->handler_context);
}

void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
{
        struct ioloop_handler_context *ctx = ioloop->handler_context;
        const int fd = io->fd;
        struct kevent ev = {fd, 0, EV_ADD | EV_CLEAR | EV_EOF, 0, 0, NULL};
        enum io_condition condition = io->condition;

        /* grow ctx->fds array if necessary */
        if ((size_t)fd >= ctx->fds_size) {
                size_t old_size = ctx->fds_size;

                ctx->fds_size = nearest_power((unsigned int)fd+1);
                i_assert(ctx->fds_size < (size_t)-1 / sizeof(int));

                ctx->fds = p_realloc(ioloop->pool, ctx->fds,
                                     sizeof(struct fdrecord) * old_size,
                                     sizeof(struct fdrecord) * ctx->fds_size);
                memset(ctx->fds + old_size, 0,
                       sizeof(struct fdrecord) * (ctx->fds_size - old_size));
        }

        if (condition & (IO_READ | IO_WRITE))
                ev.udata = io;
        if (condition & IO_ERROR)
                ctx->fds[fd].errio = io;

        if (condition & (IO_READ | IO_ERROR)) {
                ctx->fds[fd].mode |= condition;
                ev.filter = EVFILT_READ;
                kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
        }
        if (condition & (IO_WRITE | IO_ERROR)) {
                ctx->fds[fd].mode |= condition;
                ev.filter = EVFILT_WRITE;
                kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
        }
}

void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
{
        struct ioloop_handler_context *ctx = ioloop->handler_context;
        struct kevent ev = { fd, 0, EV_DELETE, 0, 0, NULL };
        struct fdrecord *const fds = ctx->fds;
        const int fd = io->fd;
        const enum io_condition condition = io->condition;

        i_assert((size_t)fd < ctx->fds_size);
        i_assert(fds[fd].mode != 0);

        if (condition & IO_ERROR)
                fds[fd].errio = NULL;
        if (condition & (IO_READ | IO_ERROR)) {
                ev.filter = EVFILT_READ;
                fds[fd].mode &= ~condition;
                if ((fds[fd].mode & (IO_READ | IO_ERROR)) == 0)
                        kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
        }
        if (condition & (IO_WRITE | IO_ERROR)) {
                ev.filter = EVFILT_WRITE;
                fds[fd].mode &= ~condition;
                if ((fds[fd].mode & (IO_WRITE | IO_ERROR)) == 0)
                        kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
        }
}

void io_loop_handler_run(struct ioloop *ioloop)
{
        struct ioloop_handler_context *ctx = ioloop->handler_context;
        struct timeval tv;
        struct timespec ts;
        unsigned int t_id;
        int msecs, ret, i;

        /* get the time left for next timeout task */
        msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
        ts.tv_sec = tv.tv_sec;
        ts.tv_nsec = tv.tv_usec * 1000;

        /* wait for events */
        ret = kevent (ctx->kq, NULL, 0, ctx->evbuf, ctx->evbuf_size, &ts);
        if (ret < 0 && errno != EINTR)
                i_fatal("kevent(): %m");

        /* execute timeout handlers */
        io_loop_handle_timeouts(ioloop);

        if (ret <= 0 || !ioloop->running) {
                /* no I/O events */
                return;
        }

        i_assert((size_t)ret <= ctx->evbuf_size);

        /* loop through all received events */
        for (i = 0; i < ret; ++i) {
                struct io *io = ctx->evbuf[i].udata;

                i_assert(ctx->evbuf[i].ident < ctx->fds_size);
                if (ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) {
                        struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;

                        t_id = t_push();
                        errio->callback(errio->context);
			if (t_pop() != t_id) {
                                i_panic("Leaked a t_pop() call"
                                        " in I/O handler %p",
					(void *)errio->callback);
			}
                }

                if (ctx->fds[ctx->evbuf[i].ident].mode & (IO_WRITE | IO_READ)) {
                        t_id = t_push();
                        io->callback(io->context);
			if (t_pop() != t_id) {
                                i_panic("Leaked a t_pop() call"
                                        " in I/O handler %p",
					(void *)io->callback);
			}
                }
        }
}

#endif



More information about the dovecot-cvs mailing list