Mercurial > dovecot > core-2.2
changeset 1729:5bf22d6bb65e HEAD
Added IO_DIR_NOTIFY and IO_FILE_NOTIFY conditions to io_add(). IO_DIR_NOTIFY
is now implemented for Linux dnotify.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 24 Aug 2003 15:43:53 +0300 |
parents | d1a6d9d24bd9 |
children | 8480f945e270 |
files | configure.in src/lib/Makefile.am src/lib/ioloop-internal.h src/lib/ioloop-notify-dn.c src/lib/ioloop-notify-none.c src/lib/ioloop-poll.c src/lib/ioloop-select.c src/lib/ioloop.c src/lib/ioloop.h |
diffstat | 9 files changed, 232 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Sun Aug 24 13:49:14 2003 +0300 +++ b/configure.in Sun Aug 24 15:43:53 2003 +0300 @@ -225,6 +225,21 @@ AC_DEFINE(IOLOOP_SELECT,, Implement I/O loop with select()) ]) +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) +], [ + AC_DEFINE(IOLOOP_NOTIFY_NONE,, No special notify support) +]) + dnl * OS specific options case "$host_os" in hpux*)
--- a/src/lib/Makefile.am Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/Makefile.am Sun Aug 24 15:43:53 2003 +0300 @@ -25,6 +25,8 @@ istream-file.c \ istream-mmap.c \ ioloop.c \ + ioloop-notify-none.c \ + ioloop-notify-dn.c \ ioloop-poll.c \ ioloop-select.c \ lib.c \
--- a/src/lib/ioloop-internal.h Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/ioloop-internal.h Sun Aug 24 15:43:53 2003 +0300 @@ -9,7 +9,8 @@ pool_t pool; int highest_fd; - struct io *ios; /* sorted by priority */ + struct io *ios; + struct io *notifys, *event_io; struct timeout *timeouts; /* sorted by next_run */ struct ioloop_handler_data *handler_data; @@ -52,10 +53,17 @@ void timeout_destroy(struct ioloop *ioloop, struct timeout **timeout_p); /* I/O handler calls */ -void io_loop_handle_add(struct ioloop *ioloop, int fd, int condition); -void io_loop_handle_remove(struct ioloop *ioloop, int fd, int condition); +void io_loop_handle_add(struct ioloop *ioloop, int fd, + enum io_condition condition); +void io_loop_handle_remove(struct ioloop *ioloop, int fd, + enum io_condition condition); void io_loop_handler_init(struct ioloop *ioloop); void io_loop_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); +void io_loop_notify_remove(struct ioloop *ioloop, struct io *io); + #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ioloop-notify-dn.c Sun Aug 24 15:43:53 2003 +0300 @@ -0,0 +1,138 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +/* Logic is pretty much based on dnotify by Oskar Liljeblad. */ + +#define _GNU_SOURCE +#include "lib.h" + +#ifdef IOLOOP_NOTIFY_DNOTIFY + +#include "ioloop-internal.h" +#include "write-full.h" + +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> + +static int event_pipe[2] = { -1, -1 }; + +static void sigrt_handler(int signo __attr_unused__, siginfo_t *si, + void *data __attr_unused__) +{ + if (write_full(event_pipe[1], &si->si_fd, sizeof(int)) < 0) + i_fatal("write_full(event_pipe) failed: %m"); +} + +static void event_callback(void *context) +{ + struct ioloop *ioloop = context; + struct io *io; + int fd, ret; + + ret = read(event_pipe[0], &fd, sizeof(fd)); + if (ret < 0) + i_fatal("read(event_pipe) failed: %m"); + if (ret != sizeof(fd)) + i_fatal("read(event_pipe) returned %d != %d", ret, sizeof(fd)); + + if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0) + i_fatal("gettimeofday(): %m"); + ioloop_time = ioloop_timeval.tv_sec; + + for (io = ioloop->notifys; io != NULL; io = io->next) { + if (io->fd == fd) { + io->callback(io->context); + break; + } + } +} + +static int dn_init(void) +{ + struct sigaction act; + + if (pipe(event_pipe) < 0) { + i_error("pipe() failed: %m"); + return FALSE; + } + + 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 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 = + io_add(event_pipe[0], IO_READ, event_callback, ioloop); + } + + if (fcntl(fd, F_SETSIG, SIGRTMIN) < 0) { + i_error("fcntl(F_SETSIG) failed: %m"); + return FALSE; + } + if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME | + DN_MULTISHOT) < 0) { + i_error("fcntl(F_NOTIFY) failed: %m"); + (void)fcntl(fd, F_SETSIG, 0); + return FALSE; + } + + io = p_new(ioloop->pool, struct io, 1); + io->fd = fd; + io->condition = condition; + + io->callback = callback; + io->context = context; + + io->next = ioloop->notifys; + ioloop->notifys = io; + return io; +} + +void io_loop_notify_remove(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; + break; + } + } + + if (fcntl(io->fd, F_SETSIG, 0) < 0) + i_error("fcntl(F_SETSIG, 0) failed: %m"); + if (fcntl(io->fd, F_NOTIFY, 0) < 0) + i_error("fcntl(F_NOTIFY, 0) failed: %m"); + + p_free(ioloop->pool, io); + + if (ioloop->notifys == NULL) { + io_remove(ioloop->event_io); + ioloop->event_io = NULL; + } +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/ioloop-notify-none.c Sun Aug 24 15:43:53 2003 +0300 @@ -0,0 +1,22 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "ioloop-internal.h" + +#ifdef IOLOOP_NOTIFY_NONE + +struct io *io_loop_notify_add(struct ioloop *ioloop __attr_unused__, + int fd __attr_unused__, + enum io_condition condition __attr_unused__, + io_callback_t *callback __attr_unused__, + void *context __attr_unused__) +{ + return FALSE; +} + +void io_loop_notify_remove(struct ioloop *ioloop __attr_unused__, + struct io *io __attr_unused__) +{ +} + +#endif
--- a/src/lib/ioloop-poll.c Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/ioloop-poll.c Sun Aug 24 15:43:53 2003 +0300 @@ -68,7 +68,8 @@ #define IO_POLL_INPUT (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL) #define IO_POLL_OUTPUT (POLLOUT|POLLERR|POLLHUP|POLLNVAL) -void io_loop_handle_add(struct ioloop *ioloop, int fd, int condition) +void io_loop_handle_add(struct ioloop *ioloop, int fd, + enum io_condition condition) { struct ioloop_handler_data *data = ioloop->handler_data; unsigned int old_size; @@ -119,7 +120,8 @@ data->fds[index].events |= IO_POLL_OUTPUT; } -void io_loop_handle_remove(struct ioloop *ioloop, int fd, int condition) +void io_loop_handle_remove(struct ioloop *ioloop, int fd, + enum io_condition condition) { struct ioloop_handler_data *data = ioloop->handler_data; int index;
--- a/src/lib/ioloop-select.c Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/ioloop-select.c Sun Aug 24 15:43:53 2003 +0300 @@ -53,7 +53,8 @@ p_free(ioloop->pool, ioloop->handler_data); } -void io_loop_handle_add(struct ioloop *ioloop, int fd, int condition) +void io_loop_handle_add(struct ioloop *ioloop, int fd, + enum io_condition condition) { i_assert(fd >= 0); @@ -66,7 +67,8 @@ FD_SET(fd, &ioloop->handler_data->write_fds); } -void io_loop_handle_remove(struct ioloop *ioloop, int fd, int condition) +void io_loop_handle_remove(struct ioloop *ioloop, int fd, + enum io_condition condition) { i_assert(fd >= 0 && fd < FD_SETSIZE); @@ -84,8 +86,8 @@ { struct timeval tv; struct io *io, **io_p; - unsigned int t_id; - int ret, fd, condition; + unsigned int t_id; + int ret; /* get the time left for next timeout task */ io_loop_get_wait_time(ioloop->timeouts, &tv, NULL); @@ -117,10 +119,7 @@ i_assert(io->fd >= 0); - fd = io->fd; - condition = io->condition; - - if (io_check_condition(fd, condition)) { + if (io_check_condition(io->fd, io->condition)) { ret--; t_id = t_push();
--- a/src/lib/ioloop.c Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/ioloop.c Sun Aug 24 15:43:53 2003 +0300 @@ -56,13 +56,19 @@ } } -struct io *io_add(int fd, int condition, io_callback_t *callback, void *context) +struct io *io_add(int fd, enum io_condition condition, + io_callback_t *callback, void *context) { struct io *io, **io_p; i_assert(fd >= 0); i_assert(callback != NULL); + if ((condition & IO_NOTIFY_MASK) != 0) { + return io_loop_notify_add(current_ioloop, fd, condition, + callback, context); + } + io = p_new(current_ioloop->pool, struct io, 1); io->fd = fd; io->condition = condition; @@ -71,9 +77,9 @@ io->context = context; if (io->fd > current_ioloop->highest_fd) - current_ioloop->highest_fd = io->fd; + current_ioloop->highest_fd = io->fd; - io_loop_handle_add(current_ioloop, io->fd, io->condition); + io_loop_handle_add(current_ioloop, io->fd, io->condition); /* have to append it, or io_destroy() breaks */ io_p = ¤t_ioloop->ios; @@ -87,14 +93,20 @@ { i_assert(io != NULL); i_assert(io->fd >= 0); + + if ((io->condition & IO_NOTIFY_MASK) != 0) { + io_loop_notify_remove(current_ioloop, io); + return; + } + i_assert(io->fd <= current_ioloop->highest_fd); - /* notify the real I/O handler */ + /* notify the real I/O handler */ io_loop_handle_remove(current_ioloop, io->fd, io->condition); - /* check if we removed the highest fd */ + /* check if we removed the highest fd */ if (io->fd == current_ioloop->highest_fd) - update_highest_fd(current_ioloop); + update_highest_fd(current_ioloop); io->destroyed = TRUE; io->fd = -1;
--- a/src/lib/ioloop.h Sun Aug 24 13:49:14 2003 +0300 +++ b/src/lib/ioloop.h Sun Aug 24 15:43:53 2003 +0300 @@ -4,13 +4,19 @@ #include <sys/time.h> #include <time.h> -#define IO_READ (1 << 0) -#define IO_WRITE (1 << 1) - struct io; struct timeout; struct ioloop; +enum io_condition { + IO_READ = 0x01, + IO_WRITE = 0x02, + IO_DIR_NOTIFY = 0x04, + IO_FILE_NOTIFY = 0x08, + + IO_NOTIFY_MASK = IO_DIR_NOTIFY | IO_FILE_NOTIFY +}; + typedef void io_callback_t(void *context); typedef void timeout_callback_t(void *context); @@ -22,8 +28,12 @@ /* I/O listeners - you can create different handlers for IO_READ and IO_WRITE, but make sure you don't create multiple handlers of same type, it's not - checked and removing one will stop the other from working as well. */ -struct io *io_add(int fd, int condition, io_callback_t *callback, void *context); + checked and removing one will stop the other from working as well. + + If IO_DIR_NOTIFY or IO_FILE_NOTIFY isn't supported by operating system + directly, this function returns NULL. */ +struct io *io_add(int fd, enum io_condition condition, + io_callback_t *callback, void *context); void io_remove(struct io *io); /* Timeout handlers */