Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib/ioloop-notify-kqueue.c @ 3958:3e9b43d0cd80 HEAD
kqueue updates. Patch by Vaclav Haisman
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 29 Jan 2006 12:32:37 +0200 |
parents | c67f77647a6e |
children | ef5595d6ddec |
line wrap: on
line source
/* * BSD kqueue() based ioloop notify handler. * * Copyright (c) 2005 Vaclav Haisman <v.haisman@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. */ #define _GNU_SOURCE #include "lib.h" #ifdef IOLOOP_NOTIFY_KQUEUE #include "ioloop-internal.h" #include "fd-close-on-exec.h" #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> #include <sys/stat.h> struct ioloop_notify_handler_context { int kq; struct io *event_io; }; static void event_callback(void *context) { struct ioloop_notify_handler_context *ctx = context; struct io *io; struct kevent ev; if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0) i_fatal("gettimeofday() failed: %m"); ioloop_time = ioloop_timeval.tv_sec; if (kevent(ctx->kq, NULL, 0, &ev, 1, 0) < 0) { i_fatal("kevent() failed: %m"); return; } io = ev.udata; io->callback(io->context); } void io_loop_notify_handler_init(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx; ctx = ioloop->notify_handler_context = p_new(ioloop->pool, struct ioloop_notify_handler_context, 1); ctx->event_io = NULL; ctx->kq = kqueue(); if (ctx->kq < 0) i_fatal("kqueue() in io_loop_notify_handler_init() failed: %m"); fd_close_on_exec(ctx->kq, TRUE); } void io_loop_notify_handler_deinit(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; if (ctx->event_io) io_remove(&ctx->event_io); if (close(ctx->kq) < 0) i_error("close(kqueue notify) failed: %m"); p_free(ioloop->pool, ctx); } static void unchain_io (struct ioloop *ioloop, struct io * io) { struct io **io_p; for (io_p = &ioloop->notifys; *io_p != NULL; io_p = &(*io_p)->next) { if (*io_p == io) { *io_p = io->next; if (io->next != NULL) io->next->prev = io->prev; io->prev = NULL; io->next = NULL; break; } } } struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path, io_callback_t *callback, void *context) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; struct kevent ev = { -1, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_REVOKE, 0, NULL }; struct io *io; int fd; struct stat sb; i_assert(callback != NULL); fd = open(path, O_RDONLY); if (fd == -1) { i_error("open(%s) for kq notify failed: %m", path); return NULL; } if (fstat(fd, &sb) < 0) { i_error("fstat(%d, %s) for kq notify failed: %m", fd, path); (void)close(fd); return NULL; } if (!S_ISDIR(sb.st_mode)) { (void)close(fd); return NULL; } fd_close_on_exec(fd, TRUE); io = p_new(ioloop->pool, struct io, 1); io->fd = fd; io->callback = callback; io->context = context; ev.ident = fd; ev.udata = io; if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) { i_error("kevent(%d, %s) for notify failed: %m", fd, path); p_free(ioloop->pool, io); return NULL; } io->next = ioloop->notifys; io->prev = NULL; if (ioloop->notifys != NULL) ioloop->notifys->prev = io; ioloop->notifys = io; if (ctx->event_io == NULL) { ctx->event_io = io_add(ctx->kq, IO_READ, event_callback, ioloop->notify_handler_context); } return io; } void io_loop_notify_remove(struct ioloop *ioloop, struct io *io) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; struct kevent ev = { io->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL }; i_assert((io->condition & IO_NOTIFY) != 0); 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) failed: %m", io->fd); unchain_io(ioloop, io); p_free(ioloop->pool, io); } #endif