[tor-commits] [tor/master] Use waitpid code to learn when a controlled process dies

nickm at torproject.org nickm at torproject.org
Sat Jun 14 15:47:50 UTC 2014


commit f8344c2d28be2489c8abadd694b5b96fe18efc02
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Apr 10 11:06:10 2014 -0400

    Use waitpid code to learn when a controlled process dies
    
    This lets us avoid sending SIGTERM to something that has already
    died, since we realize it has already died, and is a fix for the
    unix version of #8746.
---
 src/common/util.c |   46 +++++++++++++++++++++++++++++++++++++++++++---
 src/common/util.h |    9 ++++++++-
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/src/common/util.c b/src/common/util.c
index 56235aa..0a14101 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -26,6 +26,7 @@
 #include "address.h"
 #include "sandbox.h"
 #include "backtrace.h"
+#include "util_process.h"
 
 #ifdef _WIN32
 #include <io.h>
@@ -3642,7 +3643,10 @@ tor_terminate_process(process_handle_t *process_handle)
       return 0;
   }
 #else /* Unix */
-  return kill(process_handle->pid, SIGTERM);
+  if (process_handle->waitpid_cb) {
+    /* We haven't got a waitpid yet, so we can just kill off the process. */
+    return kill(process_handle->pid, SIGTERM);
+  }
 #endif
 
   return -1;
@@ -3691,6 +3695,23 @@ process_handle_new(void)
   return out;
 }
 
+#ifndef _WIN32
+/** Invoked when a process that we've launched via tor_spawn_background() has
+ * been found to have terminated.
+ */
+static void
+process_handle_waitpid_cb(int status, void *arg)
+{
+  process_handle_t *process_handle = arg;
+
+  process_handle->waitpid_exit_status = status;
+  clear_waitpid_callback(process_handle->waitpid_cb);
+  if (process_handle->status == PROCESS_STATUS_RUNNING)
+    process_handle->status = PROCESS_STATUS_NOTRUNNING;
+  process_handle->waitpid_cb = 0;
+}
+#endif
+
 /**
  * @name child-process states
  *
@@ -4007,6 +4028,10 @@ tor_spawn_background(const char *const filename, const char **argv,
             strerror(errno));
   }
 
+  process_handle->waitpid_cb = set_waitpid_callback(pid,
+                                                    process_handle_waitpid_cb,
+                                                    process_handle);
+
   process_handle->stderr_pipe = stderr_pipe[0];
   retval = close(stderr_pipe[1]);
 
@@ -4071,6 +4096,8 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
 
   if (process_handle->stderr_handle)
     fclose(process_handle->stderr_handle);
+
+  clear_waitpid_callback(process_handle->waitpid_cb);
 #endif
 
   memset(process_handle, 0x0f, sizeof(process_handle_t));
@@ -4088,7 +4115,7 @@ tor_process_handle_destroy,(process_handle_t *process_handle,
  * probably not work in Tor, because waitpid() is called in main.c to reap any
  * terminated child processes.*/
 int
-tor_get_exit_code(const process_handle_t *process_handle,
+tor_get_exit_code(process_handle_t *process_handle,
                   int block, int *exit_code)
 {
 #ifdef _WIN32
@@ -4128,7 +4155,20 @@ tor_get_exit_code(const process_handle_t *process_handle,
   int stat_loc;
   int retval;
 
-  retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG);
+  if (process_handle->waitpid_cb) {
+    /* We haven't processed a SIGCHLD yet. */
+    retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG);
+    if (retval == process_handle->pid) {
+      clear_waitpid_callback(process_handle->waitpid_cb);
+      process_handle->waitpid_cb = NULL;
+      process_handle->waitpid_exit_status = stat_loc;
+    }
+  } else {
+    /* We already got a SIGCHLD for this process, and handled it. */
+    retval = process_handle->pid;
+    stat_loc = process_handle->waitpid_exit_status;
+  }
+
   if (!block && 0 == retval) {
     /* Process has not exited */
     return PROCESS_EXIT_RUNNING;
diff --git a/src/common/util.h b/src/common/util.h
index 18dc206..97367a9 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -446,6 +446,7 @@ void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
 #define PROCESS_STATUS_ERROR -1
 
 #ifdef UTIL_PRIVATE
+struct waitpid_callback_t;
 /** Structure to represent the state of a process with which Tor is
  * communicating. The contents of this structure are private to util.c */
 struct process_handle_t {
@@ -461,6 +462,12 @@ struct process_handle_t {
   FILE *stdout_handle;
   FILE *stderr_handle;
   pid_t pid;
+  /** If the process has not given us a SIGCHLD yet, this has the
+   * waitpid_callback_t that gets invoked once it has. Otherwise this
+   * contains NULL. */
+  struct waitpid_callback_t *waitpid_cb;
+  /** The exit status reported by waitpid. */
+  int waitpid_exit_status;
 #endif // _WIN32
 };
 #endif
@@ -469,7 +476,7 @@ struct process_handle_t {
 #define PROCESS_EXIT_RUNNING 1
 #define PROCESS_EXIT_EXITED 0
 #define PROCESS_EXIT_ERROR -1
-int tor_get_exit_code(const process_handle_t *process_handle,
+int tor_get_exit_code(process_handle_t *process_handle,
                       int block, int *exit_code);
 int tor_split_lines(struct smartlist_t *sl, char *buf, int len);
 #ifdef _WIN32





More information about the tor-commits mailing list