dovecot-2.0-sslstream: master: anvil process now stays alive acr...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 13 02:55:44 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0-sslstream/rev/01676e67cf38
changeset: 10201:01676e67cf38
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Oct 26 23:45:18 2009 -0400
description:
master: anvil process now stays alive across SIGHUPs.

diffstat:

8 files changed, 211 insertions(+), 127 deletions(-)
src/master/main.c            |   16 +++-
src/master/service-anvil.c   |  161 +++++++++++++++++++++++-------------------
src/master/service-anvil.h   |   30 ++++++-
src/master/service-listen.c  |   31 ++++++--
src/master/service-monitor.c |   13 ++-
src/master/service-process.c |   52 ++++++-------
src/master/service.c         |   23 ++++--
src/master/service.h         |   12 +--

diffs (truncated from 604 to 300 lines):

diff -r 9d13e9f78d52 -r 01676e67cf38 src/master/main.c
--- a/src/master/main.c	Mon Oct 26 23:41:54 2009 -0400
+++ b/src/master/main.c	Mon Oct 26 23:45:18 2009 -0400
@@ -14,6 +14,7 @@
 #include "askpass.h"
 #include "capabilities.h"
 #include "service.h"
+#include "service-anvil.h"
 #include "service-listen.h"
 #include "service-monitor.h"
 #include "service-process.h"
@@ -295,6 +296,7 @@ sig_settings_reload(const siginfo_t *si 
 	const struct master_settings *set;
 	void **sets;
 	struct service_list *new_services;
+	struct service *service;
 	const char *error;
 
 	i_warning("SIGHUP received - reloading configuration");
@@ -334,7 +336,17 @@ sig_settings_reload(const siginfo_t *si 
 
 	/* switch to new configuration. */
 	services_monitor_stop(services);
-	(void)services_listen_using(new_services, services);
+	if (services_listen_using(new_services, services) < 0) {
+		services_monitor_start(services);
+		return;
+	}
+
+	/* anvil never dies. it just gets moved to the new services list */
+	service = service_lookup_type(services, SERVICE_TYPE_ANVIL);
+	if (service != NULL) {
+		while (service->processes != NULL)
+			service_process_destroy(service->processes);
+	}
 	services_destroy(services);
 
 	services = new_services;
@@ -416,6 +428,7 @@ static void main_deinit(void)
 	i_free(pidfile_path);
 
 	services_destroy(services);
+	service_anvil_global_deinit();
 	service_pids_deinit();
 }
 
@@ -740,6 +753,7 @@ int main(int argc, char *argv[])
 	/* create service structures from settings. if there are any errors in
 	   service configuration we'll catch it here. */
 	service_pids_init();
+	service_anvil_global_init();
 	if (services_create(set, child_process_env, &services, &error) < 0)
 		i_fatal("%s", error);
 
diff -r 9d13e9f78d52 -r 01676e67cf38 src/master/service-anvil.c
--- a/src/master/service-anvil.c	Mon Oct 26 23:41:54 2009 -0400
+++ b/src/master/service-anvil.c	Mon Oct 26 23:45:18 2009 -0400
@@ -13,17 +13,18 @@
 
 #define ANVIL_HANDSHAKE "VERSION\tanvil\t1\t0\n"
 
+struct service_anvil_global *service_anvil_global;
+
 static void
-service_list_anvil_discard_input_stop(struct service_list *service_list)
+service_list_anvil_discard_input_stop(struct service_anvil_global *anvil)
 {
-	if (service_list->anvil_io_blocking != NULL) {
-		io_remove(&service_list->anvil_io_blocking);
-		io_remove(&service_list->anvil_io_nonblocking);
+	if (anvil->io_blocking != NULL) {
+		io_remove(&anvil->io_blocking);
+		io_remove(&anvil->io_nonblocking);
 	}
 }
 
-static void
-anvil_input_fd_discard(struct service_list *service_list, int fd)
+static void anvil_input_fd_discard(struct service_anvil_global *anvil, int fd)
 {
 	char buf[1024];
 	ssize_t ret;
@@ -31,30 +32,29 @@ anvil_input_fd_discard(struct service_li
 	ret = read(fd, buf, sizeof(buf));
 	if (ret <= 0) {
 		i_error("read(anvil fd) failed: %m");
-		service_list_anvil_discard_input_stop(service_list);
+		service_list_anvil_discard_input_stop(anvil);
 	}
 }
 
-static void anvil_input_blocking_discard(struct service_list *service_list)
+static void anvil_input_blocking_discard(struct service_anvil_global *anvil)
 {
-	anvil_input_fd_discard(service_list,
-			       service_list->blocking_anvil_fd[0]);
+	anvil_input_fd_discard(anvil, anvil->blocking_fd[0]);
 }
 
-static void anvil_input_nonblocking_discard(struct service_list *service_list)
+static void anvil_input_nonblocking_discard(struct service_anvil_global *anvil)
 {
-	anvil_input_fd_discard(service_list,
-			       service_list->nonblocking_anvil_fd[0]);
+	anvil_input_fd_discard(anvil, anvil->nonblocking_fd[0]);
 }
 
-static void service_list_anvil_discard_input(struct service_list *service_list)
+static void service_list_anvil_discard_input(struct service_anvil_global *anvil)
 {
-	service_list->anvil_io_blocking =
-		io_add(service_list->blocking_anvil_fd[0], IO_READ,
-		       anvil_input_blocking_discard, service_list);
-	service_list->anvil_io_nonblocking =
-		io_add(service_list->nonblocking_anvil_fd[0], IO_READ,
-		       anvil_input_nonblocking_discard, service_list);
+	if (anvil->io_blocking != NULL)
+		return;
+
+	anvil->io_blocking = io_add(anvil->blocking_fd[0], IO_READ,
+				    anvil_input_blocking_discard, anvil);
+	anvil->io_nonblocking = io_add(anvil->nonblocking_fd[0], IO_READ,
+				       anvil_input_nonblocking_discard, anvil);
 }
 
 static int anvil_send_handshake(int fd, const char **error_r)
@@ -89,71 +89,90 @@ service_process_write_anvil_kill(int fd,
 	return 0;
 }
 
-int service_list_init_anvil(struct service_list *service_list,
-			    const char **error_r)
+void service_anvil_monitor_start(struct service_list *service_list)
 {
-	if (pipe(service_list->blocking_anvil_fd) < 0) {
-		*error_r = t_strdup_printf("pipe() failed: %m");
-		return -1;
+	struct service *service;
+
+	if (service_anvil_global->process_count == 0)
+		service_list_anvil_discard_input(service_anvil_global);
+	else {
+		service = service_lookup_type(service_list, SERVICE_TYPE_ANVIL);
+		service_process_create(service);
 	}
-	if (pipe(service_list->nonblocking_anvil_fd) < 0) {
-		(void)close(service_list->blocking_anvil_fd[0]);
-		(void)close(service_list->blocking_anvil_fd[1]);
-		*error_r = t_strdup_printf("pipe() failed: %m");
-		return -1;
-	}
-	fd_set_nonblock(service_list->nonblocking_anvil_fd[1], TRUE);
-
-	fd_close_on_exec(service_list->blocking_anvil_fd[0], TRUE);
-	fd_close_on_exec(service_list->blocking_anvil_fd[1], TRUE);
-	fd_close_on_exec(service_list->nonblocking_anvil_fd[0], TRUE);
-	fd_close_on_exec(service_list->nonblocking_anvil_fd[1], TRUE);
-
-	i_assert(service_list->anvil_kills == NULL);
-	service_list->anvil_kills =
-		service_process_notify_init(service_list->nonblocking_anvil_fd[1],
-					    service_process_write_anvil_kill);
-	return 0;
 }
 
-void services_anvil_init(struct service_list *service_list)
+void service_anvil_process_created(struct service_process *process)
 {
-	/* this can't be in _init_anvil() because we can't do io_add()s
-	   before forking with kqueue. */
-	service_list_anvil_discard_input(service_list);
+	struct service_anvil_global *anvil = service_anvil_global;
+	const char *error;
+
+	service_anvil_global->pid = process->pid;
+	service_anvil_global->uid = process->uid;
+	service_anvil_global->process_count++;
+	service_list_anvil_discard_input_stop(anvil);
+
+	if (anvil_send_handshake(anvil->blocking_fd[1], &error) < 0 ||
+	    anvil_send_handshake(anvil->nonblocking_fd[1], &error) < 0)
+		service_error(process->service, "%s", error);
 }
 
-void service_list_deinit_anvil(struct service_list *service_list)
+void service_anvil_process_destroyed(struct service_process *process)
 {
-	service_list_anvil_discard_input_stop(service_list);
-	service_process_notify_deinit(&service_list->anvil_kills);
-	if (close(service_list->blocking_anvil_fd[0]) < 0)
-		i_error("close(anvil) failed: %m");
-	if (close(service_list->blocking_anvil_fd[1]) < 0)
-		i_error("close(anvil) failed: %m");
-	if (close(service_list->nonblocking_anvil_fd[0]) < 0)
-		i_error("close(anvil) failed: %m");
-	if (close(service_list->nonblocking_anvil_fd[1]) < 0)
-		i_error("close(anvil) failed: %m");
-	service_list->blocking_anvil_fd[0] = -1;
+	i_assert(service_anvil_global->process_count > 0);
+	if (--service_anvil_global->process_count == 0)
+		service_list_anvil_discard_input(service_anvil_global);
+
+	if (service_anvil_global->pid == process->pid)
+		service_anvil_global->pid = 0;
 }
 
-void service_anvil_process_created(struct service *service)
+void service_anvil_global_init(void)
 {
-	struct service_list *list = service->list;
-	const char *error;
+	struct service_anvil_global *anvil;
 
-	service_list_anvil_discard_input_stop(service->list);
+	anvil = i_new(struct service_anvil_global, 1);
+	if (pipe(anvil->status_fd) < 0)
+		i_fatal("pipe() failed: %m");
+	if (pipe(anvil->blocking_fd) < 0)
+		i_fatal("pipe() failed: %m");
+	if (pipe(anvil->nonblocking_fd) < 0)
+		i_fatal("pipe() failed: %m");
+	fd_set_nonblock(anvil->status_fd[0], TRUE);
+	fd_set_nonblock(anvil->status_fd[1], TRUE);
+	fd_set_nonblock(anvil->nonblocking_fd[1], TRUE);
 
-	if (anvil_send_handshake(list->blocking_anvil_fd[1], &error) < 0 ||
-	    anvil_send_handshake(list->nonblocking_anvil_fd[1], &error) < 0)
-		service_error(service, "%s", error);
+	fd_close_on_exec(anvil->status_fd[0], TRUE);
+	fd_close_on_exec(anvil->status_fd[1], TRUE);
+	fd_close_on_exec(anvil->blocking_fd[0], TRUE);
+	fd_close_on_exec(anvil->blocking_fd[1], TRUE);
+	fd_close_on_exec(anvil->nonblocking_fd[0], TRUE);
+	fd_close_on_exec(anvil->nonblocking_fd[1], TRUE);
+
+	anvil->kills =
+		service_process_notify_init(anvil->nonblocking_fd[1],
+					    service_process_write_anvil_kill);
+	service_anvil_global = anvil;
 }
 
-void service_anvil_process_destroyed(struct service *service)
+void service_anvil_global_deinit(void)
 {
-	if (service->process_count == 0 &&
-	    service->list->anvil_io_blocking == NULL &&
-	    service->list->blocking_anvil_fd[0] != -1)
-		service_list_anvil_discard_input(service->list);
+	struct service_anvil_global *anvil = service_anvil_global;
+
+	service_list_anvil_discard_input_stop(anvil);
+	service_process_notify_deinit(&anvil->kills);
+	if (close(anvil->blocking_fd[0]) < 0)
+		i_error("close(anvil) failed: %m");
+	if (close(anvil->blocking_fd[1]) < 0)
+		i_error("close(anvil) failed: %m");
+	if (close(anvil->nonblocking_fd[0]) < 0)
+		i_error("close(anvil) failed: %m");
+	if (close(anvil->nonblocking_fd[1]) < 0)
+		i_error("close(anvil) failed: %m");
+	if (close(anvil->status_fd[0]) < 0)
+		i_error("close(anvil) failed: %m");
+	if (close(anvil->status_fd[1]) < 0)
+		i_error("close(anvil) failed: %m");
+	i_free(anvil);
+
+	service_anvil_global = NULL;
 }
diff -r 9d13e9f78d52 -r 01676e67cf38 src/master/service-anvil.h
--- a/src/master/service-anvil.h	Mon Oct 26 23:41:54 2009 -0400
+++ b/src/master/service-anvil.h	Mon Oct 26 23:45:18 2009 -0400
@@ -1,12 +1,30 @@
 #ifndef SERVICE_ANVIL_H
 #define SERVICE_ANVIL_H
 
-int service_list_init_anvil(struct service_list *service_list,
-			    const char **error_r);
-void service_list_deinit_anvil(struct service_list *service_list);
-void services_anvil_init(struct service_list *service_list);
+struct service_anvil_global {
+	pid_t pid;
+	unsigned int uid;
 
-void service_anvil_process_created(struct service *service);
-void service_anvil_process_destroyed(struct service *service);
+	int status_fd[2];
+	/* passed to child processes */
+	int blocking_fd[2];
+	/* used by master process to notify about dying processes */
+	int nonblocking_fd[2];
+
+	struct service_process_notify *kills;
+	struct io *io_blocking, *io_nonblocking;
+
+	unsigned int process_count;
+};
+
+extern struct service_anvil_global *service_anvil_global;
+
+void service_anvil_monitor_start(struct service_list *service_list);


More information about the dovecot-cvs mailing list