[PATCH] Processes that spawn other processes should wait for their children to exit before exiting due to a signal.

Chris Bieneman beanz at apple.com
Thu Apr 30 15:51:21 PDT 2015


Updating based on feedback from majnemer, ddunbar, and silvas.


http://reviews.llvm.org/D9420

Files:
  lib/Support/Unix/Program.inc

Index: lib/Support/Unix/Program.inc
===================================================================
--- lib/Support/Unix/Program.inc
+++ lib/Support/Unix/Program.inc
@@ -21,8 +21,10 @@
 #include "llvm/Config/config.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -61,10 +63,15 @@
 #endif
 #endif
 
+#include <vector>
+
 namespace llvm {
 
 using namespace sys;
 
+static bool ProgramSignalHandlerAdded = false;
+static ManagedStatic<std::vector<ProcessInfo>> ChildPIDs;
+
 ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {}
 
 ErrorOr<std::string> sys::findProgramByName(StringRef Name,
@@ -177,6 +184,18 @@
 
 }
 
+// If a process that spawns other processes (like the clang driver) gets killed
+// via a SIGINT, it should wait until its children exit before returning from
+// the signal handler. This prevents the child processes from getting
+// re-parented, which causes problems for build systems that are the parent of
+// clang processes.
+static void WaitForChildren(void *) {
+  if (ChildPIDs.isConstructed())
+    for (auto PI : *ChildPIDs)
+      Wait(PI, /*SecondsUntilTerminate=*/0, /*WaitUntilTerminate=*/true,
+           /*ErrMsg=*/nullptr);
+}
+
 static bool Execute(ProcessInfo &PI, StringRef Program, const char **args,
                     const char **envp, const StringRef **redirects,
                     unsigned memoryLimit, std::string *ErrMsg) {
@@ -187,6 +206,11 @@
     return false;
   }
 
+  if (!ProgramSignalHandlerAdded) {
+    AddSignalHandler(WaitForChildren, nullptr);
+    ProgramSignalHandlerAdded = true;
+  }
+
   // If this OS has posix_spawn and there is no memory limit being implied, use
   // posix_spawn.  It is more efficient than fork/exec.
 #ifdef HAVE_POSIX_SPAWN
@@ -250,6 +274,7 @@
      return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err);
 
     PI.Pid = PID;
+    ChildPIDs->push_back(PI);
 
     return true;
   }
@@ -314,12 +339,16 @@
   }
 
   PI.Pid = child;
+  ChildPIDs->push_back(PI);
 
   return true;
 }
 
 namespace llvm {
 
+// This is assumed to be safe to call from within a signal handler. That means
+// it can't allocate or de-allocate memory or use any C interfaces not listed in
+// the sigaction man page.
 ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
                       bool WaitUntilTerminates, std::string *ErrMsg) {
 #ifdef HAVE_SYS_WAIT_H

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D9420.24778.patch
Type: text/x-patch
Size: 2589 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150430/27784649/attachment.bin>


More information about the llvm-commits mailing list