changeset 13252:32315c24992c

Replaced "ioloop log" with a more generic "ioloop context". The context can call multiple callbacks that can do anything they want, including setting the log prefix.
author Timo Sirainen <tss@iki.fi>
date Tue, 16 Aug 2011 18:33:27 +0300
parents 390f69281fb8
children 69cf3bb0b8e8
files src/lib-storage/mail-storage-service.c src/lib/ioloop-internal.h src/lib/ioloop-notify-dn.c src/lib/ioloop-notify-inotify.c src/lib/ioloop-notify-kqueue.c src/lib/ioloop.c src/lib/ioloop.h
diffstat 7 files changed, 181 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/mail-storage-service.c	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib-storage/mail-storage-service.c	Tue Aug 16 18:33:27 2011 +0300
@@ -41,6 +41,8 @@
 struct mail_storage_service_ctx {
 	pool_t pool;
 	struct master_service *service;
+	const char *default_log_prefix;
+
 	struct auth_master_connection *conn;
 	struct auth_master_user_list_ctx *auth_list;
 	const struct setting_parser_info **set_roots;
@@ -55,9 +57,13 @@
 
 struct mail_storage_service_user {
 	pool_t pool;
+	struct mail_storage_service_ctx *service_ctx;
 	struct mail_storage_service_input input;
 	enum mail_storage_service_flags flags;
 
+	struct ioloop_context *ioloop_ctx;
+	const char *log_prefix;
+
 	const char *system_groups_user, *uid_source, *gid_source;
 	const struct mail_user_settings *user_set;
 	const struct setting_parser_info *user_info;
@@ -564,6 +570,20 @@
 	return str_c(ret);
 }
 
+static void mail_storage_service_io_activate(void *context)
+{
+	struct mail_storage_service_user *user = context;
+
+	i_set_failure_prefix(user->log_prefix);
+}
+
+static void mail_storage_service_io_deactivate(void *context)
+{
+	struct mail_storage_service_user *user = context;
+
+	i_set_failure_prefix(user->service_ctx->default_log_prefix);
+}
+
 static void
 mail_storage_service_init_log(struct mail_storage_service_ctx *ctx,
 			      struct mail_storage_service_user *user)
@@ -571,17 +591,20 @@
 	ctx->log_initialized = TRUE;
 	T_BEGIN {
 		string_t *str;
-		struct ioloop_log *log;
 
 		str = t_str_new(256);
 		var_expand(str, user->user_set->mail_log_prefix,
 			   get_var_expand_table(ctx->service, &user->input));
-		master_service_init_log(ctx->service, str_c(str));
+		user->log_prefix = p_strdup(user->pool, str_c(str));
+	} T_END;
+
+	master_service_init_log(ctx->service, user->log_prefix);
 
-		log = io_loop_log_new(current_ioloop);
-		io_loop_log_set_prefix(log, str_c(str));
-		io_loop_log_unref(&log);
-	} T_END;
+	user->ioloop_ctx = io_loop_context_new(current_ioloop);
+	io_loop_context_add_callbacks(user->ioloop_ctx,
+				      mail_storage_service_io_activate,
+				      mail_storage_service_io_deactivate,
+				      user);
 }
 
 static void mail_storage_service_time_moved(time_t old_time, time_t new_time)
@@ -657,10 +680,9 @@
 	if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT) == 0) {
 		/* note: we may not have read any settings yet, so this logging
 		   may still be going to wrong location */
-		const char *log_prefix = t_strconcat(service->name, ": ", NULL);
-
-		master_service_init_log(service, log_prefix);
-		io_loop_set_default_log_prefix(current_ioloop, log_prefix);
+		ctx->default_log_prefix =
+			p_strconcat(pool, service->name, ": ", NULL);
+		master_service_init_log(service, ctx->default_log_prefix);
 	}
 	dict_drivers_register_builtin();
 	return ctx;
@@ -871,6 +893,7 @@
 
 	user = p_new(user_pool, struct mail_storage_service_user, 1);
 	memset(user_r, 0, sizeof(user_r));
+	user->service_ctx = ctx;
 	user->pool = user_pool;
 	user->input = *input;
 	user->input.userdb_fields = NULL;
@@ -1050,6 +1073,9 @@
 	struct mail_storage_service_user *user = *_user;
 
 	*_user = NULL;
+
+	io_loop_context_remove_callbacks(user->ioloop_ctx, user);
+	io_loop_context_unref(&user->ioloop_ctx);
 	settings_parser_deinit(&user->set_parser);
 	pool_unref(&user->pool);
 }
--- a/src/lib/ioloop-internal.h	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop-internal.h	Tue Aug 16 18:33:27 2011 +0300
@@ -11,8 +11,7 @@
 struct ioloop {
         struct ioloop *prev;
 
-	struct ioloop_log *cur_log;
-	char *default_log_prefix;
+	struct ioloop_context *cur_ctx;
 
 	struct io_file *io_files;
 	struct io_file *next_io_file;
@@ -35,7 +34,7 @@
         void *context;
 
 	struct ioloop *ioloop;
-	struct ioloop_log *log;
+	struct ioloop_context *ctx;
 };
 
 struct io_file {
@@ -58,13 +57,19 @@
         void *context;
 
 	struct ioloop *ioloop;
-	struct ioloop_log *log;
+	struct ioloop_context *ctx;
 };
 
-struct ioloop_log {
+struct ioloop_context_callback {
+	io_callback_t *activate;
+	io_callback_t *deactivate;
+	void *context;
+};
+
+struct ioloop_context {
 	int refcount;
-	char *prefix;
 	struct ioloop *ioloop;
+	ARRAY_DEFINE(callbacks, struct ioloop_context_callback);
 };
 
 int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r);
@@ -81,4 +86,7 @@
 void io_loop_notify_remove(struct io *io);
 void io_loop_notify_handler_deinit(struct ioloop *ioloop);
 
+void io_loop_context_activate(struct ioloop_context *ctx);
+void io_loop_context_deactivate(struct ioloop_context *ctx);
+
 #endif
--- a/src/lib/ioloop-notify-dn.c	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop-notify-dn.c	Tue Aug 16 18:33:27 2011 +0300
@@ -87,7 +87,7 @@
 	for (i = 0; i < ret; i++) {
 		io = io_notify_fd_find(&ctx->fd_ctx, fd_buf[i]);
 		if (io != NULL)
-			io->io.callback(io->io.context);
+			io_loop_call_io(&io->io);
 	}
 }
 
--- a/src/lib/ioloop-notify-inotify.c	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop-notify-inotify.c	Tue Aug 16 18:33:27 2011 +0300
@@ -70,7 +70,7 @@
 				   EINVAL */
 				io->fd = -1;
 			}
-			io->io.callback(io->io.context);
+			io_loop_call_io(&io->io);
 		}
 	}
 	if (pos != ret)
--- a/src/lib/ioloop-notify-kqueue.c	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop-notify-kqueue.c	Tue Aug 16 18:33:27 2011 +0300
@@ -71,7 +71,7 @@
 		/* there can be multiple events for a single io.
 		   call the callback only once if that happens. */
 		if (io->refcount == 2 && io->io.callback != NULL)
-			io->io.callback(io->io.context);
+			io_loop_call_io(&io->io);
 
 		if (--io->refcount == 0)
 			i_free(io);
--- a/src/lib/ioloop.c	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop.c	Tue Aug 16 18:33:27 2011 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "time-util.h"
 #include "ioloop-internal.h"
 
@@ -44,9 +45,9 @@
 	io->refcount = 1;
 	io->fd = fd;
 
-	if (io->io.ioloop->cur_log != NULL) {
-		io->io.log = io->io.ioloop->cur_log;
-		io_loop_log_ref(io->io.log);
+	if (io->io.ioloop->cur_ctx != NULL) {
+		io->io.ctx = io->io.ioloop->cur_ctx;
+		io_loop_context_ref(io->io.ctx);
 	}
 
 	if (io->io.ioloop->handler_context == NULL)
@@ -89,8 +90,8 @@
 	   kqueue code relies on this. */
 	io->callback = NULL;
 
-	if (io->log != NULL)
-		io_loop_log_unref(&io->log);
+	if (io->ctx != NULL)
+		io_loop_context_unref(&io->ctx);
 
 	if ((io->condition & IO_NOTIFY) != 0)
 		io_loop_notify_remove(io);
@@ -150,9 +151,9 @@
 	timeout->callback = callback;
 	timeout->context = context;
 
-	if (timeout->ioloop->cur_log != NULL) {
-		timeout->log = timeout->ioloop->cur_log;
-		io_loop_log_ref(timeout->log);
+	if (timeout->ioloop->cur_ctx != NULL) {
+		timeout->ctx = timeout->ioloop->cur_ctx;
+		io_loop_context_ref(timeout->ctx);
 	}
 
 	timeout_update_next(timeout, timeout->ioloop->running ?
@@ -163,8 +164,8 @@
 
 static void timeout_free(struct timeout *timeout)
 {
-	if (timeout->log != NULL)
-		io_loop_log_unref(&timeout->log);
+	if (timeout->ctx != NULL)
+		io_loop_context_unref(&timeout->ctx);
 	i_free(timeout);
 }
 
@@ -345,21 +346,16 @@
 		/* update timeout's next_run and reposition it in the queue */
 		timeout_reset_timeval(timeout, &tv_call);
 
-		if (timeout->log != NULL) {
-			ioloop->cur_log = timeout->log;
-			io_loop_log_ref(ioloop->cur_log);
-			i_set_failure_prefix(timeout->log->prefix);
-		}
+		if (timeout->ctx != NULL)
+			io_loop_context_activate(timeout->ctx);
                 t_id = t_push();
 		timeout->callback(timeout->context);
 		if (t_pop() != t_id) {
 			i_panic("Leaked a t_pop() call in timeout handler %p",
 				(void *)timeout->callback);
 		}
-		if (ioloop->cur_log != NULL) {
-			io_loop_log_unref(&ioloop->cur_log);
-			i_set_failure_prefix(ioloop->default_log_prefix);
-		}
+		if (ioloop->cur_ctx != NULL)
+			io_loop_context_activate(ioloop->cur_ctx);
 	}
 }
 
@@ -375,21 +371,16 @@
 	struct ioloop *ioloop = io->ioloop;
 	unsigned int t_id;
 
-	if (io->log != NULL) {
-		ioloop->cur_log = io->log;
-		io_loop_log_ref(ioloop->cur_log);
-		i_set_failure_prefix(io->log->prefix);
-	}
+	if (io->ctx != NULL)
+		io_loop_context_activate(io->ctx);
 	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);
 	}
-	if (ioloop->cur_log != NULL) {
-		io_loop_log_unref(&ioloop->cur_log);
-		i_set_failure_prefix(ioloop->default_log_prefix);
-	}
+	if (ioloop->cur_ctx != NULL)
+		io_loop_context_deactivate(ioloop->cur_ctx);
 }
 
 void io_loop_run(struct ioloop *ioloop)
@@ -397,8 +388,8 @@
 	if (ioloop->handler_context == NULL)
 		io_loop_initialize_handler(ioloop);
 
-	if (ioloop->cur_log != NULL)
-		io_loop_log_unref(&ioloop->cur_log);
+	if (ioloop->cur_ctx != NULL)
+		io_loop_context_unref(&ioloop->cur_ctx);
 
 	ioloop->running = TRUE;
 	while (ioloop->running)
@@ -480,7 +471,6 @@
         i_assert(ioloop == current_ioloop);
 	current_ioloop = current_ioloop->prev;
 
-	i_free(ioloop->default_log_prefix);
 	i_free(ioloop);
 }
 
@@ -495,59 +485,117 @@
 	current_ioloop = ioloop;
 }
 
-struct ioloop_log *io_loop_log_new(struct ioloop *ioloop)
+struct ioloop_context *io_loop_context_new(struct ioloop *ioloop)
 {
-	struct ioloop_log *log;
+	struct ioloop_context *ctx;
 
-	i_assert(ioloop->default_log_prefix != NULL);
+	ctx = i_new(struct ioloop_context, 1);
+	ctx->refcount = 2;
+	ctx->ioloop = ioloop;
+	i_array_init(&ctx->callbacks, 4);
 
-	log = i_new(struct ioloop_log, 1);
-	log->refcount = 2;
-	log->prefix = i_strdup("");
+	if (ioloop->cur_ctx != NULL)
+		io_loop_context_unref(&ioloop->cur_ctx);
+	ioloop->cur_ctx = ctx;
+	return ctx;
+}
 
-	log->ioloop = ioloop;
-	if (ioloop->cur_log != NULL)
-		io_loop_log_unref(&ioloop->cur_log);
-	ioloop->cur_log = log;
-	return log;
+void io_loop_context_ref(struct ioloop_context *ctx)
+{
+	i_assert(ctx->refcount > 0);
+
+	ctx->refcount++;
 }
 
-void io_loop_log_ref(struct ioloop_log *log)
+void io_loop_context_unref(struct ioloop_context **_ctx)
 {
-	i_assert(log->refcount > 0);
+	struct ioloop_context *ctx = *_ctx;
+
+	*_ctx = NULL;
+
+	i_assert(ctx->refcount > 0);
+	if (--ctx->refcount > 0)
+		return;
+
+	/* cur_ctx itself keeps a reference */
+	i_assert(ctx->ioloop->cur_ctx != ctx);
 
-	log->refcount++;
+	array_free(&ctx->callbacks);
+	i_free(ctx);
+}
+
+void io_loop_context_add_callbacks(struct ioloop_context *ctx,
+				   io_callback_t *activate,
+				   io_callback_t *deactivate, void *context)
+{
+	struct ioloop_context_callback cb;
+
+	memset(&cb, 0, sizeof(cb));
+	cb.activate = activate;
+	cb.deactivate = deactivate;
+	cb.context = context;
+
+	array_append(&ctx->callbacks, &cb, 1);
 }
 
-void io_loop_log_unref(struct ioloop_log **_log)
+void io_loop_context_remove_callbacks(struct ioloop_context *ctx,
+				      void *context)
 {
-	struct ioloop_log *log = *_log;
-
-	*_log = NULL;
+	struct ioloop_context_callback *cb;
 
-	i_assert(log->refcount > 0);
-	if (--log->refcount > 0)
-		return;
-
-	/* cur_log itself keeps a reference */
-	i_assert(log->ioloop->cur_log != log);
-
-	i_free(log->prefix);
-	i_free(log);
+	array_foreach_modifiable(&ctx->callbacks, cb) {
+		if (cb->context == context) {
+			/* simply mark it as deleted, since we could get
+			   here from activate/deactivate loop */
+			cb->activate = NULL;
+			cb->deactivate = NULL;
+			cb->context = NULL;
+			return;
+		}
+	}
+	i_panic("io_loop_context_remove_callbacks() context not found");
 }
 
-void io_loop_log_set_prefix(struct ioloop_log *log, const char *prefix)
+static void
+io_loop_context_remove_deleted_callbacks(struct ioloop_context *ctx)
 {
-	i_free(log->prefix);
-	log->prefix = i_strdup(prefix);
+	const struct ioloop_context_callback *cbs;
+	unsigned int i, count;
+
+	cbs = array_get(&ctx->callbacks, &count);
+	for (i = 0; i < count; ) {
+		if (cbs[i].activate != NULL)
+			i++;
+		else {
+			array_delete(&ctx->callbacks, i, 1);
+			cbs = array_get(&ctx->callbacks, &count);
+		}
+	}
 }
 
-void io_loop_set_default_log_prefix(struct ioloop *ioloop, const char *prefix)
+void io_loop_context_activate(struct ioloop_context *ctx)
 {
-	i_assert(prefix != NULL);
+	const struct ioloop_context_callback *cb;
+
+	ctx->ioloop->cur_ctx = ctx;
+	io_loop_context_ref(ctx);
+	array_foreach(&ctx->callbacks, cb) {
+		if (cb->activate != NULL)
+			cb->activate(cb->context);
+	}
+}
 
-	i_free(ioloop->default_log_prefix);
-	ioloop->default_log_prefix = i_strdup(prefix);
+void io_loop_context_deactivate(struct ioloop_context *ctx)
+{
+	const struct ioloop_context_callback *cb;
+
+	array_foreach(&ctx->callbacks, cb) {
+		if (cb->deactivate != NULL)
+			cb->deactivate(cb->context);
+	}
+	ctx->ioloop->cur_ctx = NULL;
+	io_loop_context_remove_deleted_callbacks(ctx);
+	io_loop_context_unref(&ctx);
 }
 
 struct io *io_loop_move_io(struct io **_io)
--- a/src/lib/ioloop.h	Tue Aug 16 18:27:40 2011 +0300
+++ b/src/lib/ioloop.h	Tue Aug 16 18:33:27 2011 +0300
@@ -100,16 +100,21 @@
 /* Change the current_ioloop. */
 void io_loop_set_current(struct ioloop *ioloop);
 
-/* This log is used for all further I/O and timeout callbacks that are added
-   until returning to ioloop. */
-struct ioloop_log *io_loop_log_new(struct ioloop *ioloop);
-void io_loop_log_ref(struct ioloop_log *log);
-void io_loop_log_unref(struct ioloop_log **log);
-/* Set the log's prefix. Note that this doesn't immediately call
-   i_set_failure_prefix(). */
-void io_loop_log_set_prefix(struct ioloop_log *log, const char *prefix);
-/* Set the default log prefix to use outside callbacks. */
-void io_loop_set_default_log_prefix(struct ioloop *ioloop, const char *prefix);
+/* This context is used for all further I/O and timeout callbacks that are
+   added until returning to ioloop. When a callback is called, this context is
+   again activated. */
+struct ioloop_context *io_loop_context_new(struct ioloop *ioloop);
+void io_loop_context_ref(struct ioloop_context *ctx);
+void io_loop_context_unref(struct ioloop_context **ctx);
+/* Call the activate callback when this context is activated (I/O callback is
+   about to be called), and the deactivate callback when the context is
+   deactivated (I/O callback has returned). You can add multiple callbacks. */
+void io_loop_context_add_callbacks(struct ioloop_context *ctx,
+				   io_callback_t *activate,
+				   io_callback_t *deactivate, void *context);
+/* Remove callbacks with the given context. */
+void io_loop_context_remove_callbacks(struct ioloop_context *ctx,
+				      void *context);
 
 /* Move the given I/O into the current I/O loop if it's not already
    there. New I/O is returned, while the old one is freed. */