Signal handlers should never call syslog(), as that can raise signals of its own. Instead, call the syslog() from the master process. To avoid waking up unnecessarily, a pipe is set up that is only ever written to by child_handler(), when a child disconnects, as suggested per Junio. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- On Sat, 5 Jul 2008, Junio C Hamano wrote: > Johannes Schindelin <Johannes.Schindelin@xxxxxx> writes: > > > Junio wrote: > >> Another way would be to set up a pipe to ourself that is > >> included in the poll() and write a byte to the pipe from the signal > >> handler. > > > > It still would need to break out of the poll(), in which case > > the effect would be _exactly_ the same,... > > I do not think so. Okay. Note that we still have to check for dead children in check_max_connections(), and since child_handler() knows nothing about that, it still will write to the pipe, waking up the loop unnecessarily. But that will be rare. This is no longer as trivial as I wanted it to be, so I'd appreciate a few eyeballs on this patch. daemon.c | 69 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 48 insertions(+), 21 deletions(-) diff --git a/daemon.c b/daemon.c index 63cd12c..620a288 100644 --- a/daemon.c +++ b/daemon.c @@ -16,6 +16,7 @@ static int log_syslog; static int verbose; static int reuseaddr; +static int child_handler_pipe[2]; static const char daemon_usage[] = "git-daemon [--verbose] [--syslog] [--export-all]\n" @@ -694,23 +695,47 @@ static void kill_some_children(int signo, unsigned start, unsigned stop) } } +static void check_dead_children(void) +{ + unsigned spawned, reaped, deleted; + + spawned = children_spawned; + reaped = children_reaped; + deleted = children_deleted; + + while (deleted < reaped) { + pid_t pid = dead_child[deleted % MAX_CHILDREN]; + const char *dead = pid < 0 ? " (with error)" : ""; + + if (pid < 0) + pid = -pid; + + /* XXX: Custom logging, since we don't wanna getpid() */ + if (verbose) { + if (log_syslog) + syslog(LOG_INFO, "[%d] Disconnected%s", + pid, dead); + else + fprintf(stderr, "[%d] Disconnected%s\n", + pid, dead); + } + remove_child(pid, deleted, spawned); + deleted++; + } + children_deleted = deleted; +} + static void check_max_connections(void) { for (;;) { int active; - unsigned spawned, reaped, deleted; + unsigned spawned, deleted; + + check_dead_children(); spawned = children_spawned; - reaped = children_reaped; deleted = children_deleted; - while (deleted < reaped) { - pid_t pid = dead_child[deleted % MAX_CHILDREN]; - remove_child(pid, deleted, spawned); - deleted++; - } - children_deleted = deleted; - active = spawned - deleted; if (active <= max_connections) break; @@ -760,18 +785,11 @@ static void child_handler(int signo) if (pid > 0) { unsigned reaped = children_reaped; + if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) + pid = -pid; dead_child[reaped % MAX_CHILDREN] = pid; children_reaped = reaped + 1; - /* XXX: Custom logging, since we don't wanna getpid() */ - if (verbose) { - const char *dead = ""; - if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) - dead = " (with error)"; - if (log_syslog) - syslog(LOG_INFO, "[%d] Disconnected%s", pid, dead); - else - fprintf(stderr, "[%d] Disconnected%s\n", pid, dead); - } + write(child_handler_pipe[1], &status, 1); continue; } break; @@ -917,19 +935,24 @@ static int service_loop(int socknum, int *socklist) struct pollfd *pfd; int i; - pfd = xcalloc(socknum, sizeof(struct pollfd)); + if (pipe(child_handler_pipe) < 0) + die ("Could not set up pipe for child handler"); + + pfd = xcalloc(socknum + 1, sizeof(struct pollfd)); for (i = 0; i < socknum; i++) { pfd[i].fd = socklist[i]; pfd[i].events = POLLIN; } + pfd[socknum].fd = child_handler_pipe[0]; + pfd[socknum].events = POLLIN; signal(SIGCHLD, child_handler); for (;;) { int i; - if (poll(pfd, socknum, -1) < 0) { + if (poll(pfd, socknum + 1, -1) < 0) { if (errno != EINTR) { error("poll failed, resuming: %s", strerror(errno)); @@ -937,6 +960,10 @@ static int service_loop(int socknum, int *socklist) } continue; } + if (pfd[socknum].revents & POLLIN) { + read(child_handler_pipe[0], &i, 1); + check_dead_children(); + } for (i = 0; i < socknum; i++) { if (pfd[i].revents & POLLIN) { -- 1.5.6.1.300.gca3f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html