]> mj.ucw.cz Git - libucw.git/commitdiff
Solved mainloop race by selfpipe
authorMichal Vaner <vorner@ucw.cz>
Sat, 7 Mar 2009 21:40:10 +0000 (22:40 +0100)
committerMichal Vaner <vorner@ucw.cz>
Sat, 7 Mar 2009 21:40:10 +0000 (22:40 +0100)
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

index 9a39abd7d3338ae11720298ba5e1d9d43c2dbb30..c68089d616c180a4623c28d923c237dfa8f21446 100644 (file)
@@ -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();