dovecot-2.1: master: Wait for services to stop listening before ...

dovecot at dovecot.org dovecot at dovecot.org
Sat Nov 5 19:07:39 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/6894298ae5fd
changeset: 13662:6894298ae5fd
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Nov 05 19:17:59 2011 +0200
description:
master: Wait for services to stop listening before unlinking the pid file.

diffstat:

 src/master/main.c            |  19 ++++++++++++++++---
 src/master/service-monitor.c |  41 +++++++++++++++++++++++++++++++++++++----
 src/master/service-monitor.h |   2 +-
 src/master/service.c         |   7 ++++---
 src/master/service.h         |   3 ++-
 5 files changed, 60 insertions(+), 12 deletions(-)

diffs (188 lines):

diff -r 21145b853d64 -r 6894298ae5fd src/master/main.c
--- a/src/master/main.c	Sat Nov 05 17:59:11 2011 +0200
+++ b/src/master/main.c	Sat Nov 05 19:17:59 2011 +0200
@@ -330,7 +330,7 @@
 			 services->config->config_file_path);
 
 	/* switch to new configuration. */
-	services_monitor_stop(services);
+	services_monitor_stop(services, FALSE);
 	if (services_listen_using(new_services, services) < 0) {
 		services_monitor_start(services);
 		return;
@@ -342,7 +342,7 @@
 		while (service->processes != NULL)
 			service_process_destroy(service->processes);
 	}
-	services_destroy(services);
+	services_destroy(services, FALSE);
 
 	services = new_services;
         services_monitor_start(services);
@@ -455,13 +455,26 @@
 	services_monitor_start(services);
 }
 
+static void global_dead_pipe_close(void)
+{
+	if (close(global_master_dead_pipe_fd[0]) < 0)
+		i_error("close(global dead pipe) failed: %m");
+	if (close(global_master_dead_pipe_fd[1]) < 0)
+		i_error("close(global dead pipe) failed: %m");
+	global_master_dead_pipe_fd[0] = -1;
+	global_master_dead_pipe_fd[1] = -1;
+}
+
 static void main_deinit(void)
 {
+	/* kill services and wait for them to die before unlinking pid file */
+	global_dead_pipe_close();
+	services_destroy(services, TRUE);
+
 	if (unlink(pidfile_path) < 0)
 		i_error("unlink(%s) failed: %m", pidfile_path);
 	i_free(pidfile_path);
 
-	services_destroy(services);
 	service_anvil_global_deinit();
 	service_pids_deinit();
 }
diff -r 21145b853d64 -r 6894298ae5fd src/master/service-monitor.c
--- a/src/master/service-monitor.c	Sat Nov 05 17:59:11 2011 +0200
+++ b/src/master/service-monitor.c	Sat Nov 05 19:17:59 2011 +0200
@@ -23,6 +23,7 @@
 #define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
 #define SERVICE_DROP_WARN_INTERVAL_SECS 60
 #define SERVICE_DROP_TIMEOUT_MSECS (10*1000)
+#define MAX_DIE_WAIT_SECS 5
 
 static void service_monitor_start_extra_avail(struct service *service);
 static void service_status_more(struct service_process *process,
@@ -171,8 +172,10 @@
 	if (ret <= 0) {
 		if (ret == 0)
 			service_error(service, "read(status) failed: EOF");
+		else if (errno != EAGAIN)
+			service_error(service, "read(status) failed: %m");
 		else
-			service_error(service, "read(status) failed: %m");
+			return;
 		service_monitor_stop(service);
 		return;
 	}
@@ -467,7 +470,28 @@
 		timeout_remove(&service->to_throttle);
 }
 
-void services_monitor_stop(struct service_list *service_list)
+static void services_monitor_wait(struct service_list *service_list)
+{
+	struct service *const *servicep;
+	time_t max_wait_time = time(NULL) + MAX_DIE_WAIT_SECS;
+	bool finished;
+
+	for (;;) {
+		finished = TRUE;
+		services_monitor_reap_children();
+		array_foreach(&service_list->services, servicep) {
+			if ((*servicep)->status_fd[0] != -1)
+				service_status_input(*servicep);
+			if ((*servicep)->process_avail > 0)
+				finished = FALSE;
+		}
+		if (finished || time(NULL) > max_wait_time)
+			break;
+		usleep(100000);
+	}
+}
+
+void services_monitor_stop(struct service_list *service_list, bool wait)
 {
 	struct service *const *services;
 
@@ -480,6 +504,13 @@
 		service_list->master_dead_pipe_fd[1] = -1;
 	}
 
+	if (wait) {
+		/* we've notified all children that the master is dead.
+		   now wait for the children to either die or to tell that
+		   they're no longer listening for new connections */
+		services_monitor_wait(service_list);
+	}
+
 	array_foreach(&service_list->services, services)
 		service_monitor_stop(*services);
 
@@ -516,7 +547,8 @@
 		service = process->service;
 		if (status == 0) {
 			/* success */
-			if (service->listen_pending)
+			if (service->listen_pending &&
+			    !service->list->destroying)
 				service_monitor_listen_start(service);
 			throttle = FALSE;
 		} else {
@@ -535,7 +567,8 @@
 			service_monitor_throttle(service);
 		service_stopped = service->status_fd[0] == -1;
 		if (!service_stopped) {
-			service_monitor_start_extra_avail(service);
+			if (!service->list->destroying)
+				service_monitor_start_extra_avail(service);
 			if (service->to_throttle == NULL)
 				service_monitor_listen_start(service);
 		}
diff -r 21145b853d64 -r 6894298ae5fd src/master/service-monitor.h
--- a/src/master/service-monitor.h	Sat Nov 05 17:59:11 2011 +0200
+++ b/src/master/service-monitor.h	Sat Nov 05 19:17:59 2011 +0200
@@ -5,7 +5,7 @@
 void services_monitor_start(struct service_list *service_list);
 
 /* Stop services. */
-void services_monitor_stop(struct service_list *service_list);
+void services_monitor_stop(struct service_list *service_list, bool wait);
 
 /* Call after SIGCHLD has been detected */
 void services_monitor_reap_children(void);
diff -r 21145b853d64 -r 6894298ae5fd src/master/service.c
--- a/src/master/service.c	Sat Nov 05 17:59:11 2011 +0200
+++ b/src/master/service.c	Sat Nov 05 19:17:59 2011 +0200
@@ -615,12 +615,13 @@
 	}
 }
 
-void services_destroy(struct service_list *service_list)
+void services_destroy(struct service_list *service_list, bool wait)
 {
 	/* make sure we log if child processes died unexpectedly */
-        services_monitor_reap_children();
+	service_list->destroying = TRUE;
+	services_monitor_reap_children();
 
-	services_monitor_stop(service_list);
+	services_monitor_stop(service_list, wait);
 
 	if (service_list->refcount > 1 &&
 	    service_list->service_set->shutdown_clients) {
diff -r 21145b853d64 -r 6894298ae5fd src/master/service.h
--- a/src/master/service.h	Sat Nov 05 17:59:11 2011 +0200
+++ b/src/master/service.h	Sat Nov 05 19:17:59 2011 +0200
@@ -126,6 +126,7 @@
 
 	ARRAY_DEFINE(services, struct service *);
 
+	unsigned int destroying:1;
 	unsigned int destroyed:1;
 	unsigned int sigterm_sent:1;
 	unsigned int sigterm_sent_to_log:1;
@@ -138,7 +139,7 @@
 		    struct service_list **services_r, const char **error_r);
 
 /* Destroy services */
-void services_destroy(struct service_list *service_list);
+void services_destroy(struct service_list *service_list, bool wait);
 
 void service_list_ref(struct service_list *service_list);
 void service_list_unref(struct service_list *service_list);


More information about the dovecot-cvs mailing list