Mercurial > dovecot > core-2.2
changeset 3482:465c465c66be HEAD
Added inotify patch by Johannes Berg and did some restructuring to
ioloop notify internals.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 12 Jul 2005 18:40:33 +0300 |
parents | 2d631ab1d90e |
children | 84a4f150bd00 |
files | configure.in src/lib/Makefile.am src/lib/ioloop-internal.h src/lib/ioloop-notify-dn.c src/lib/ioloop-notify-inotify.c src/lib/ioloop-notify-none.c src/lib/ioloop.c |
diffstat | 7 files changed, 321 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Tue Jul 12 17:43:44 2005 +0300 +++ b/configure.in Tue Jul 12 18:40:33 2005 +0300 @@ -1,4 +1,4 @@ -AC_INIT(dovecot, 1.0-test73, [dovecot@dovecot.org]) +AC_INIT(dovecot, 1.0-test77, [dovecot@dovecot.org]) AC_CONFIG_SRCDIR([src]) AC_CONFIG_HEADERS([config.h]) @@ -57,6 +57,13 @@ ioloop=$withval, ioloop=) +AC_ARG_WITH(notify, +[ --with-notify=IOLOOP Specify the file system notification method to use + (dnotify, inotify, none; + default dnotify if compilable, otherwise none)], + notify=$withval, + notify=) + AC_ARG_WITH(passwd, [ --with-passwd Build with /etc/passwd support (default)], if test x$withval = xno; then @@ -324,20 +331,59 @@ ioloop="select" fi -dnl * dnotify? -AC_TRY_COMPILE([ - #define _GNU_SOURCE - #include <fcntl.h> - #include <signal.h> - #include <unistd.h> -], [ - fcntl(0, F_SETSIG, SIGRTMIN); - fcntl(0, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME | DN_MULTISHOT); -], [ - AC_DEFINE(IOLOOP_NOTIFY_DNOTIFY,, Use Linux dnotify) -], [ +have_notify=no + +if test "$notify" = "none"; then AC_DEFINE(IOLOOP_NOTIFY_NONE,, No special notify support) -]) +fi + +if test "$notify" = "" || test "$notify" = "dnotify"; then + dnl * dnotify? + AC_TRY_COMPILE([ + #define _GNU_SOURCE + #include <fcntl.h> + #include <signal.h> + #include <unistd.h> + ], [ + fcntl(0, F_SETSIG, SIGRTMIN); + fcntl(0, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME | DN_MULTISHOT); + ], [ + AC_DEFINE(IOLOOP_NOTIFY_DNOTIFY,, Use Linux dnotify) + notify=dnotify + ], [ + if test "$notify" = "dnotify"; then + AC_MSG_ERROR([dnotify requested but not available]) + fi + notify=none + AC_DEFINE(IOLOOP_NOTIFY_NONE,, No special notify support) + ]) +fi + +if test "$notify" = "inotify"; then + dnl * inotify? + AC_TRY_COMPILE([ + #define _GNU_SOURCE + #include <sys/ioctl.h> + #include <fcntl.h> + #include <linux/inotify.h> + ], [ + struct inotify_watch_request req; + int wd, dev_fd; + char * fn = "/tmp"; + dev_fd = open ("/dev/inotify", O_RDONLY); + req.fd = open (fn, O_RDONLY); + if (req.fd < 0) return -1; + req.mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_MODIFY | IN_ACCESS; + wd = ioctl (dev_fd, INOTIFY_WATCH, &req); + close(req.fd); + ioctl (dev_fd, INOTIFY_IGNORE, &wd); + ], [ + AC_DEFINE(IOLOOP_NOTIFY_INOTIFY,, Use Linux inotify) + ], [ + AC_MSG_ERROR([inotify requested but not available, check for existence of <linux/inotify.h>]) + notify=none + ]) +fi dnl * GLIBC? AC_TRY_COMPILE([ @@ -1409,6 +1455,7 @@ echo "Install prefix ...................... : $prefix" echo "File offsets ........................ : ${offt_bits}bit" echo "I/O loop method ..................... : $ioloop" +echo "File change notification method ..... : $notify" echo "Building with SSL support ........... : $have_ssl" echo "Building with IPv6 support .......... : $want_ipv6" echo "Building with pop3 server ........... : $want_pop3d"
--- a/src/lib/Makefile.am Tue Jul 12 17:43:44 2005 +0300 +++ b/src/lib/Makefile.am Tue Jul 12 18:40:33 2005 +0300 @@ -29,6 +29,7 @@ ioloop.c \ ioloop-notify-none.c \ ioloop-notify-dn.c \ + ioloop-notify-inotify.c \ ioloop-poll.c \ ioloop-select.c \ ioloop-epoll.c \
--- a/src/lib/ioloop-internal.h Tue Jul 12 17:43:44 2005 +0300 +++ b/src/lib/ioloop-internal.h Tue Jul 12 18:40:33 2005 +0300 @@ -9,11 +9,12 @@ pool_t pool; struct io *ios; - struct io *notifys, *event_io; + struct io *notifys; struct io *next_io; struct timeout *timeouts; /* sorted by next_run */ struct ioloop_handler_data *handler_data; + struct ioloop_notify_handler_context *notify_handler_context; unsigned int running:1; }; @@ -26,6 +27,8 @@ io_callback_t *callback; void *context; + + int notify_context; }; struct timeout { @@ -55,6 +58,9 @@ 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_handler_deinit(struct ioloop *ioloop); + struct io *io_loop_notify_add(struct ioloop *ioloop, int fd, enum io_condition condition, io_callback_t *callback, void *context);
--- a/src/lib/ioloop-notify-dn.c Tue Jul 12 17:43:44 2005 +0300 +++ b/src/lib/ioloop-notify-dn.c Tue Jul 12 18:40:33 2005 +0300 @@ -14,6 +14,10 @@ #include <unistd.h> #include <fcntl.h> +struct ioloop_notify_handler_context { + struct io *event_io; +}; + static int event_pipe[2] = { -1, -1 }; static void sigrt_handler(int signo __attr_unused__, siginfo_t *si, @@ -52,50 +56,19 @@ } } -static int dn_init(void) -{ - struct sigaction act; - - if (pipe(event_pipe) < 0) { - i_error("pipe() failed: %m"); - return FALSE; - } - - net_set_nonblock(event_pipe[0], TRUE); - net_set_nonblock(event_pipe[1], TRUE); - - /* SIGIO is sent if queue gets full. we'll just ignore it. */ - signal(SIGIO, SIG_IGN); - - act.sa_sigaction = sigrt_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; - - if (sigaction(SIGRTMIN, &act, NULL) < 0) { - i_error("sigaction(SIGRTMIN) failed: %m"); - close(event_pipe[0]); - close(event_pipe[1]); - return FALSE; - } - - return TRUE; -} - struct io *io_loop_notify_add(struct ioloop *ioloop, int fd, enum io_condition condition, io_callback_t *callback, void *context) { + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; struct io *io; if ((condition & IO_FILE_NOTIFY) != 0) return NULL; - if (event_pipe[0] == -1) { - if (!dn_init()) - return NULL; - } - if (ioloop->event_io == NULL) { - ioloop->event_io = + if (ctx->event_io == NULL) { + ctx->event_io = io_add(event_pipe[0], IO_READ, event_callback, ioloop); } @@ -124,6 +97,8 @@ void io_loop_notify_remove(struct ioloop *ioloop, struct io *io) { + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; struct io **io_p; for (io_p = &ioloop->notifys; *io_p != NULL; io_p = &(*io_p)->next) { @@ -141,9 +116,53 @@ p_free(ioloop->pool, io); if (ioloop->notifys == NULL) { - io_remove(ioloop->event_io); - ioloop->event_io = NULL; + io_remove(ctx->event_io); + ctx->event_io = NULL; } } +void io_loop_notify_handler_init(struct ioloop *ioloop) +{ + struct ioloop_notify_handler_context *ctx; + struct sigaction act; + + i_assert(event_pipe[0] == -1); + + ctx = ioloop->notify_handler_context = + i_new(struct ioloop_notify_handler_context, 1); + + if (pipe(event_pipe) < 0) { + i_fatal("pipe() failed: %m"); + return; + } + + net_set_nonblock(event_pipe[0], TRUE); + net_set_nonblock(event_pipe[1], TRUE); + + /* SIGIO is sent if queue gets full. we'll just ignore it. */ + signal(SIGIO, SIG_IGN); + + act.sa_sigaction = sigrt_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; + + if (sigaction(SIGRTMIN, &act, NULL) < 0) + i_fatal("sigaction(SIGRTMIN) failed: %m"); +} + +void io_loop_notify_handler_deinit(struct ioloop *ioloop __attr_unused__) +{ + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; + + signal(SIGRTMIN, SIG_IGN); + + if (close(event_pipe[0]) < 0) + i_error("close(event_pipe[0]) failed: %m"); + if (close(event_pipe[1]) < 0) + i_error("close(event_pipe[1]) failed: %m"); + + i_free(ctx); +} + #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ioloop-notify-inotify.c Tue Jul 12 18:40:33 2005 +0300 @@ -0,0 +1,186 @@ +/* Copyright (C) 2005 Johannes Berg */ + +#define _GNU_SOURCE +#include "lib.h" + +#ifdef IOLOOP_NOTIFY_INOTIFY + +#include "ioloop-internal.h" +#include "buffer.h" +#include "network.h" + +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/inotify.h> + +#define INITIAL_INOTIFY_BUFLEN (FILENAME_MAX + sizeof(struct inotify_event)) +#define MAXIMAL_INOTIFY_BUFLEN (32*1024) + +struct ioloop_notify_handler_context { + int inotify_fd; + + struct io *event_io; + + buffer_t *buf; +}; + +static int event_read_next(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; + + 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"); + + 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) { + if (io->notify_context == event->wd) { + io->callback(io->context); + break; + } + } + + 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); + } + + return TRUE; +} + +static void event_callback(void *context) +{ + struct ioloop *ioloop = context; + + while (event_read_next(ioloop)) ; +} + +struct io *io_loop_notify_add(struct ioloop *ioloop, int fd, + enum io_condition condition, + io_callback_t *callback, void *context) +{ + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; + struct io *io; + struct inotify_watch_request req; + int added = FALSE; + int watchdescriptor; + + if ((condition & IO_FILE_NOTIFY) != 0) + return NULL; + + if (ctx->event_io == NULL) { + added = TRUE; + ctx->event_io = io_add(ctx->inotify_fd, IO_READ, + event_callback, ioloop); + } + + /* now set up the notification request and shoot it off */ + req.fd = fd; + req.mask = IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE | IN_MODIFY; + watchdescriptor = ioctl(ctx->inotify_fd, INOTIFY_WATCH, &req); + + if (watchdescriptor < 0) { + i_error("ioctl(INOTIFY_WATCH) failed: %m"); + if (added) { + io_remove(ctx->event_io); + ctx->event_io = NULL; + } + return NULL; + } + + io = p_new(ioloop->pool, struct io, 1); + io->fd = fd; + io->condition = condition; + + io->callback = callback; + io->context = context; + io->notify_context = watchdescriptor; + + io->next = ioloop->notifys; + ioloop->notifys = io; + return io; +} + +void io_loop_notify_remove(struct ioloop *ioloop, struct io *io) +{ + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; + 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; + break; + } + } + + if (ioctl(ctx->inotify_fd, INOTIFY_IGNORE, &io->notify_context) < 0) + i_error("ioctl(INOTIFY_IGNORE) failed: %m"); + + p_free(ioloop->pool, io); + + if (ioloop->notifys == NULL) { + io_remove(ctx->event_io); + ctx->event_io = NULL; + } +} + +void io_loop_notify_handler_init(struct ioloop *ioloop) +{ + struct ioloop_notify_handler_context *ctx; + + ctx = ioloop->notify_handler_context = + i_new(struct ioloop_notify_handler_context, 1); + + ctx->inotify_fd = open("/dev/inotify", O_RDONLY); + if (ctx->inotify_fd < 0) + i_fatal("open(/dev/inotify) failed: %m"); + + ctx->buf = buffer_create_dynamic(default_pool, INITIAL_INOTIFY_BUFLEN); +} + +void io_loop_notify_handler_deinit(struct ioloop *ioloop) +{ + struct ioloop_notify_handler_context *ctx = + ioloop->notify_handler_context; + + if (close(ctx->inotify_fd) < 0) + i_error("close(/dev/inotify) failed: %m"); + + buffer_free(ctx->buf); + i_free(ctx); +} + +#endif
--- a/src/lib/ioloop-notify-none.c Tue Jul 12 17:43:44 2005 +0300 +++ b/src/lib/ioloop-notify-none.c Tue Jul 12 18:40:33 2005 +0300 @@ -19,4 +19,12 @@ { } +void io_loop_notify_handler_init(struct ioloop *ioloop __attr_unused__) +{ +} + +void io_loop_notify_handler_deinit(struct ioloop *ioloop __attr_unused__) +{ +} + #endif
--- a/src/lib/ioloop.c Tue Jul 12 17:43:44 2005 +0300 +++ b/src/lib/ioloop.c Tue Jul 12 18:40:33 2005 +0300 @@ -247,6 +247,7 @@ ioloop->pool = pool; io_loop_handler_init(ioloop); + io_loop_notify_handler_init(ioloop); ioloop->prev = current_ioloop; current_ioloop = ioloop; @@ -275,6 +276,7 @@ timeout_destroy(ioloop, &ioloop->timeouts); } + io_loop_notify_handler_deinit(ioloop); io_loop_handler_deinit(ioloop); /* ->prev won't work unless loops are destroyed in create order */