From: Timo Sirainen Date: Wed, 15 Dec 2010 17:07:01 +0000 (+0000) Subject: master-child API change: Use a separate fd for tracking when master dies. X-Git-Tag: 2.0.9~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbcba924a745c938260fd39cb284175b75f8eaf2;p=thirdparty%2Fdovecot%2Fcore.git master-child API change: Use a separate fd for tracking when master dies. This works around a Linux performance problem where when one process writes to status fd all the other processes of the same service type wake up. --- diff --git a/src/lib-master/master-interface.h b/src/lib-master/master-interface.h index 005abc5e87..2a6a79f62e 100644 --- a/src/lib-master/master-interface.h +++ b/src/lib-master/master-interface.h @@ -68,13 +68,16 @@ enum master_login_state { /* Shared pipe to master, used to send master_status reports */ #define MASTER_STATUS_FD 5 +/* Pipe to master, used to detect when it dies. (MASTER_STATUS_FD would have + been fine for this, except it's inefficient in Linux) */ +#define MASTER_DEAD_FD 6 /* First file descriptor where process is expected to be listening. The file descriptor count is given in -s parameter, defaulting to 1. master_status.available_count reports how many accept()s we're still accepting. Once no children are listening, master will do it and create new child processes when needed. */ -#define MASTER_LISTEN_FD_FIRST 6 +#define MASTER_LISTEN_FD_FIRST 7 /* Timeouts: base everything on how long we can wait for login clients. */ #define MASTER_LOGIN_TIMEOUT_SECS (3*60) diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c index 5925bb63fb..250f479171 100644 --- a/src/lib-master/master-service.c +++ b/src/lib-master/master-service.c @@ -375,7 +375,7 @@ void master_service_init_finish(struct master_service *service) master_service_set_service_count(service, count); /* start listening errors for status fd, it means master died */ - service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR, + service->io_status_error = io_add(MASTER_DEAD_FD, IO_ERROR, master_status_error, service); } else { master_service_set_client_limit(service, 1); diff --git a/src/master/common.h b/src/master/common.h index ee7fc8beec..00ea6e17f6 100644 --- a/src/master/common.h +++ b/src/master/common.h @@ -9,7 +9,7 @@ extern uid_t master_uid; extern gid_t master_gid; extern bool core_dumps_disabled; extern const char *ssl_manual_key_password; -extern int null_fd; +extern int null_fd, master_dead_pipe_fd[2]; extern struct service_list *services; void process_exec(const char *cmd, const char *extra_args[]) ATTR_NORETURN; diff --git a/src/master/main.c b/src/master/main.c index 350c9ca241..59bbec73a1 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -42,7 +42,7 @@ uid_t master_uid; gid_t master_gid; bool core_dumps_disabled; const char *ssl_manual_key_password; -int null_fd; +int null_fd, master_dead_pipe_fd[2]; struct service_list *services; static char *pidfile_path; @@ -412,7 +412,7 @@ static void main_init(const struct master_settings *set) lib_signals_set_handler(SIGUSR1, TRUE, sig_log_reopen, NULL); lib_signals_set_handler(SIGCHLD, TRUE, sig_reap_children, NULL); lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL); - lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL); + lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL); create_pid_file(pidfile_path); create_config_symlink(set); @@ -712,6 +712,10 @@ int main(int argc, char *argv[]) i_fatal("Can't open /dev/null: %m"); fd_close_on_exec(null_fd, TRUE); } while (null_fd <= STDERR_FILENO); + if (pipe(master_dead_pipe_fd) < 0) + i_fatal("pipe() failed: %m"); + fd_close_on_exec(master_dead_pipe_fd[0], TRUE); + fd_close_on_exec(master_dead_pipe_fd[1], TRUE); set = master_settings_read(); if (ask_key_pass) { diff --git a/src/master/service-process.c b/src/master/service-process.c index de2a12ecd6..38d7f18e70 100644 --- a/src/master/service-process.c +++ b/src/master/service-process.c @@ -116,6 +116,7 @@ service_dup_fds(struct service *service) break; } dup2_append(&dups, service->status_fd[1], MASTER_STATUS_FD); + dup2_append(&dups, master_dead_pipe_fd[1], MASTER_DEAD_FD); if (service->type == SERVICE_TYPE_LOG) { /* keep stderr as-is. this is especially important when