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 #endif @@ -61,10 +63,15 @@ #endif #endif +#include + namespace llvm { using namespace sys; +static bool ProgramSignalHandlerAdded = false; +static ManagedStatic> ChildPIDs; + ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} ErrorOr 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