From da14d7b5a593c3f8446be8f1f83a7eb61964bb99 Mon Sep 17 00:00:00 2001 From: Michal Vaner Date: Sat, 7 Mar 2009 22:40:10 +0100 Subject: [PATCH] Solved mainloop race by selfpipe A better solution would be using ppoll, but it is not generally available. It will be detected and used if available soon. --- ucw/mainloop.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/ucw/mainloop.c b/ucw/mainloop.c index 9a39abd7..c68089d6 100644 --- a/ucw/mainloop.c +++ b/ucw/mainloop.c @@ -33,6 +33,8 @@ static uns main_file_cnt; static uns main_poll_table_obsolete, main_poll_table_size; static struct pollfd *main_poll_table; static uns main_sigchld_set_up; +static sig_atomic_t chld_received = 0; +static int sig_pipe_recv, sig_pipe_send; void main_get_time(void) @@ -252,6 +254,20 @@ static void main_sigchld_handler(int x UNUSED) { DBG("SIGCHLD received"); + chld_received = 1; + if(write(sig_pipe_send, "c", 1) == -1 && errno != EAGAIN) + die("Could not write to selfpipe: %m"); +} + +static int +dummy_read_handler(struct main_file *mp) +{ + char *buffer[1024]; + ssize_t result = read(mp->fd, buffer, 1024); + if(result == -1 && errno != EAGAIN) + die("Could not read from selfpipe: %m"); + file_chg(mp); + return result == 1024; } void @@ -263,12 +279,24 @@ process_add(struct main_process *mp) clist_add_tail(&main_process_list, &mp->n); if (!main_sigchld_set_up) { + int pipe_result[2]; + if(pipe2(pipe_result, O_NONBLOCK|O_CLOEXEC) == -1) + die("Could not create selfpipe:%m"); + sig_pipe_recv = pipe_result[0]; + sig_pipe_send = pipe_result[1]; + static struct main_file self_pipe; + self_pipe = (struct main_file) { + .fd = sig_pipe_recv, + .read_handler = dummy_read_handler + }; + file_add(&self_pipe); struct sigaction sa; bzero(&sa, sizeof(sa)); sa.sa_handler = main_sigchld_handler; sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; sigaction(SIGCHLD, &sa, NULL); main_sigchld_set_up = 1; + chld_received = 1; // The signal may have come before the handler } } @@ -396,11 +424,12 @@ main_loop(void) wake = 0; if (main_poll_table_obsolete) main_rebuild_poll_table(); - if (!clist_empty(&main_process_list)) + if (chld_received && !clist_empty(&main_process_list)) { int stat; pid_t pid; wake = MIN(wake, main_now + 10000); + chld_received = 0; while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) { DBG("MAIN: Child %d exited with status %x", pid, stat); @@ -417,7 +446,6 @@ main_loop(void) wake = 0; } } - /* FIXME: Here is a small race window where SIGCHLD can come unnoticed. */ if ((tm = clist_head(&main_timer_list)) && tm->expires < wake) wake = tm->expires; main_get_time(); -- 2.39.2