Implementing Thomas Bushnell's suggestion to work around the signal race without...
authorChristian Grothoff <christian@grothoff.org>
Sat, 26 Nov 2011 14:52:20 +0000 (14:52 +0000)
committerChristian Grothoff <christian@grothoff.org>
Sat, 26 Nov 2011 14:52:20 +0000 (14:52 +0000)
configure.ac
src/util/os_priority.c
src/util/scheduler.c

index 9f00d10eda7bc610af611c3ef9942b909748d461..8fc49aadc5b2e11f91afa58a116445aad6c0e1b6 100644 (file)
@@ -613,7 +613,6 @@ AC_CHECK_MEMBER([struct sockaddr_in.sin_len],
 # Checks for library functions.
 AC_FUNC_CLOSEDIR_VOID
 AC_FUNC_FORK
-AC_FUNC_VFORK
 AC_PROG_GCC_TRADITIONAL
 AC_FUNC_MEMCMP
 AC_FUNC_SELECT_ARGTYPES
index a7ce0c5e5d767cc78c09c5e407303e785b94973a..3b3b022b918cfaaa7c222807875bc7fdca2fbac4 100644 (file)
@@ -595,11 +595,7 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
                                        &fd_stdin_write, sizeof (int));
   }
 
-#if HAVE_WORKING_VFORK
-  ret = vfork ();
-#else
   ret = fork ();
-#endif
   if (ret != 0)
   {
     if (ret == -1)
@@ -611,22 +607,6 @@ GNUNET_OS_start_process_va (struct GNUNET_DISK_PipeHandle *pipe_stdin,
     }
     else
     {
-
-#if HAVE_WORKING_VFORK
-      /* let's hope vfork actually works; for some extreme cases (including
-       * a testcase) we need 'execvp' to have run before we return, since
-       * we may send a signal to the process next and we don't want it
-       * to be caught by OUR signal handler (but either by the default
-       * handler or the actual handler as installed by the process itself). */
-#else
-      /* let's give the child process a chance to run execvp, 1s should
-       * be plenty in practice */
-      if (pipe_stdout != NULL)
-        GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
-      if (pipe_stdin != NULL)
-        GNUNET_DISK_pipe_close_end (pipe_stdin, GNUNET_DISK_PIPE_END_READ);
-      sleep (1);
-#endif
       gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
       gnunet_proc->pid = ret;
 #if ENABLE_WINDOWS_WORKAROUNDS
@@ -906,11 +886,7 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
       GNUNET_array_append (lscp, ls, k);
     GNUNET_array_append (lscp, ls, -1);
   }
-#if HAVE_WORKING_VFORK
-  ret = vfork ();
-#else
   ret = fork ();
-#endif
   if (ret != 0)
   {
     if (ret == -1)
@@ -922,17 +898,6 @@ GNUNET_OS_start_process_v (const int *lsocks, const char *filename,
     }
     else
     {
-#if HAVE_WORKING_VFORK
-      /* let's hope vfork actually works; for some extreme cases (including
-       * a testcase) we need 'execvp' to have run before we return, since
-       * we may send a signal to the process next and we don't want it
-       * to be caught by OUR signal handler (but either by the default
-       * handler or the actual handler as installed by the process itself). */
-#else
-      /* let's give the child process a chance to run execvp, 1s should
-       * be plenty in practice */
-      sleep (1);
-#endif
       gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
       gnunet_proc->pid = ret;
 #if ENABLE_WINDOWS_WORKAROUNDS
index 7254b1700548f6c10029606b89dcc0437afe9522..d4a11fc8a04353a6fb98fd48a998afe967342840 100644 (file)
@@ -701,6 +701,12 @@ run_ready (struct GNUNET_NETWORK_FDSet *rs, struct GNUNET_NETWORK_FDSet *ws)
  */
 static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
 
+/**
+ * Process ID of this process at the time we installed the various
+ * signal handlers.
+ */
+static pid_t my_pid;
+
 /**
  * Signal handler called for SIGPIPE.
  */
@@ -720,6 +726,9 @@ sighandler_shutdown ()
   static char c;
   int old_errno = errno;        /* backup errno */
 
+  if (getpid() != my_pid)
+    exit(1); /* we have fork'ed since the signal handler was created,
+               ignore the signal, see https://gnunet.org/vfork discussion */
   GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
                           (shutdown_pipe_handle, GNUNET_DISK_PIPE_END_WRITE),
                           &c, sizeof (c));
@@ -799,6 +808,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   pr = GNUNET_DISK_pipe_handle (shutdown_pipe_handle,
                                 GNUNET_DISK_PIPE_END_READ);
   GNUNET_assert (pr != NULL);
+  my_pid = getpid ();
   shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
   shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
 #ifndef MINGW