[dovecot-cvs] dovecot/src/lib Makefile.am, 1.51, 1.52 ioloop-internal.h, 1.12, 1.13 ioloop-notify-dn.c, 1.3, 1.4 ioloop-notify-inotify.c, NONE, 1.1 ioloop-notify-none.c, 1.2, 1.3 ioloop.c, 1.25, 1.26

cras at dovecot.org cras at dovecot.org
Tue Jul 12 18:40:36 EEST 2005


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

Modified Files:
	Makefile.am ioloop-internal.h ioloop-notify-dn.c 
	ioloop-notify-none.c ioloop.c 
Added Files:
	ioloop-notify-inotify.c 
Log Message:
Added inotify patch by Johannes Berg and did some restructuring to
ioloop notify internals.



Index: Makefile.am
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/Makefile.am,v
retrieving revision 1.51
retrieving revision 1.52
diff -u -d -r1.51 -r1.52
--- Makefile.am	12 Jul 2005 13:07:47 -0000	1.51
+++ Makefile.am	12 Jul 2005 15:40:33 -0000	1.52
@@ -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 \

Index: ioloop-internal.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-internal.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- ioloop-internal.h	25 Aug 2004 12:27:44 -0000	1.12
+++ ioloop-internal.h	12 Jul 2005 15:40:33 -0000	1.13
@@ -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);

Index: ioloop-notify-dn.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-dn.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- ioloop-notify-dn.c	5 Sep 2004 22:06:26 -0000	1.3
+++ ioloop-notify-dn.c	12 Jul 2005 15:40:33 -0000	1.4
@@ -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

--- NEW FILE: ioloop-notify-inotify.c ---
/* 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

Index: ioloop-notify-none.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop-notify-none.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ioloop-notify-none.c	21 Oct 2004 02:27:12 -0000	1.2
+++ ioloop-notify-none.c	12 Jul 2005 15:40:33 -0000	1.3
@@ -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

Index: ioloop.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib/ioloop.c,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- ioloop.c	25 Aug 2004 12:27:44 -0000	1.25
+++ ioloop.c	12 Jul 2005 15:40:33 -0000	1.26
@@ -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 */



More information about the dovecot-cvs mailing list