Mercurial > dovecot > core-2.2
changeset 13662:6894298ae5fd
master: Wait for services to stop listening before unlinking the pid file.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 05 Nov 2011 19:17:59 +0200 |
parents | 21145b853d64 |
children | 131e44d50d35 |
files | src/master/main.c src/master/service-monitor.c src/master/service-monitor.h src/master/service.c src/master/service.h |
diffstat | 5 files changed, 60 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- 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(); }
--- 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); }
--- 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);
--- 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) {
--- 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);