diff options
Diffstat (limited to 'llvm/lib/Support/Unix/Program.inc')
-rw-r--r-- | llvm/lib/Support/Unix/Program.inc | 87 |
1 files changed, 71 insertions, 16 deletions
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc index 520685a0e987..8f41fc015163 100644 --- a/llvm/lib/Support/Unix/Program.inc +++ b/llvm/lib/Support/Unix/Program.inc @@ -15,6 +15,8 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// +#include "llvm/Support/Program.h" + #include "Unix.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" @@ -59,8 +61,7 @@ #endif #endif -namespace llvm { - +using namespace llvm; using namespace sys; ProcessInfo::ProcessInfo() : Pid(0), ReturnCode(0) {} @@ -70,8 +71,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name, assert(!Name.empty() && "Must have a name!"); // Use the given path verbatim if it contains any slashes; this matches // the behavior of sh(1) and friends. - if (Name.find('/') != StringRef::npos) - return std::string(Name); + if (Name.find('/') != StringRef::npos) return std::string(Name); SmallVector<StringRef, 16> EnvironmentPaths; if (Paths.empty()) @@ -88,7 +88,7 @@ ErrorOr<std::string> sys::findProgramByName(StringRef Name, SmallString<128> FilePath(Path); sys::path::append(FilePath, Name); if (sys::fs::can_execute(FilePath.c_str())) - return std::string(FilePath.str()); // Found the executable! + return std::string(FilePath.str()); // Found the executable! } return errc::no_such_file_or_directory; } @@ -101,7 +101,7 @@ static bool RedirectIO(Optional<StringRef> Path, int FD, std::string* ErrMsg) { // Redirect empty paths to /dev/null File = "/dev/null"; else - File = *Path; + File = std::string(*Path); // Open the file int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); @@ -162,8 +162,6 @@ static void SetMemoryLimits(unsigned size) { #endif } -} - static std::vector<const char *> toNullTerminatedCStringArray(ArrayRef<StringRef> Strings, StringSaver &Saver) { std::vector<const char *> Result; @@ -213,7 +211,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, std::string *RedirectsStr[3] = {nullptr, nullptr, nullptr}; for (int I = 0; I < 3; ++I) { if (Redirects[I]) { - RedirectsStorage[I] = *Redirects[I]; + RedirectsStorage[I] = std::string(*Redirects[I]); RedirectsStr[I] = &RedirectsStorage[I]; } } @@ -304,7 +302,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program, } // Execute! - std::string PathStr = Program; + std::string PathStr = std::string(Program); if (Envp != nullptr) execve(PathStr.c_str(), const_cast<char **>(Argv), const_cast<char **>(Envp)); @@ -331,9 +329,54 @@ static bool Execute(ProcessInfo &PI, StringRef Program, } namespace llvm { +namespace sys { + +#ifndef _AIX +using ::wait4; +#else +static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage); +#endif -ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, - bool WaitUntilTerminates, std::string *ErrMsg) { +} // namespace sys +} // namespace llvm + +#ifdef _AIX +#ifndef _ALL_SOURCE +extern "C" pid_t (wait4)(pid_t pid, int *status, int options, + struct rusage *usage); +#endif +pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options, + struct rusage *usage) { + assert(pid > 0 && "Only expecting to handle actual PID values!"); + assert((options & ~WNOHANG) == 0 && "Expecting WNOHANG at most!"); + assert(usage && "Expecting usage collection!"); + + // AIX wait4 does not work well with WNOHANG. + if (!(options & WNOHANG)) + return ::wait4(pid, status, options, usage); + + // For WNOHANG, we use waitid (which supports WNOWAIT) until the child process + // has terminated. + siginfo_t WaitIdInfo; + WaitIdInfo.si_pid = 0; + int WaitIdRetVal = + waitid(P_PID, pid, &WaitIdInfo, WNOWAIT | WEXITED | options); + + if (WaitIdRetVal == -1 || WaitIdInfo.si_pid == 0) + return WaitIdRetVal; + + assert(WaitIdInfo.si_pid == pid); + + // The child has already terminated, so a blocking wait on it is okay in the + // absence of indiscriminate `wait` calls from the current process (which + // would cause the call here to fail with ECHILD). + return ::wait4(pid, status, options & ~WNOHANG, usage); +} +#endif + +ProcessInfo llvm::sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, + bool WaitUntilTerminates, std::string *ErrMsg, + Optional<ProcessStatistics> *ProcStat) { struct sigaction Act, Old; assert(PI.Pid && "invalid pid to wait on, process not started?"); @@ -349,6 +392,7 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, Act.sa_handler = TimeOutHandler; sigemptyset(&Act.sa_mask); sigaction(SIGALRM, &Act, &Old); + // FIXME The alarm signal may be delivered to another thread. alarm(SecondsToWait); } else if (SecondsToWait == 0) WaitPidOptions = WNOHANG; @@ -356,9 +400,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, // Parent process: Wait for the child process to terminate. int status; ProcessInfo WaitResult; + rusage Info; + if (ProcStat) + ProcStat->reset(); do { - WaitResult.Pid = waitpid(ChildPid, &status, WaitPidOptions); + WaitResult.Pid = sys::wait4(ChildPid, &status, WaitPidOptions, &Info); } while (WaitUntilTerminates && WaitResult.Pid == -1 && errno == EINTR); if (WaitResult.Pid != PI.Pid) { @@ -375,6 +422,8 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, sigaction(SIGALRM, &Old, nullptr); // Wait for child to die + // FIXME This could grab some other child process out from another + // waiting thread and then leave a zombie anyway. if (wait(&status) != ChildPid) MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); else @@ -396,6 +445,13 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, sigaction(SIGALRM, &Old, nullptr); } + if (ProcStat) { + std::chrono::microseconds UserT = toDuration(Info.ru_utime); + std::chrono::microseconds KernelT = toDuration(Info.ru_stime); + uint64_t PeakMemory = static_cast<uint64_t>(Info.ru_maxrss); + *ProcStat = ProcessStatistics{UserT + KernelT, UserT, PeakMemory}; + } + // Return the proper exit status. Detect error conditions // so we can return -1 for them and set ErrMsg informatively. int result = 0; @@ -430,12 +486,12 @@ ProcessInfo sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait, return WaitResult; } -std::error_code sys::ChangeStdinToBinary() { +std::error_code llvm::sys::ChangeStdinToBinary() { // Do nothing, as Unix doesn't differentiate between text and binary. return std::error_code(); } -std::error_code sys::ChangeStdoutToBinary() { +std::error_code llvm::sys::ChangeStdoutToBinary() { // Do nothing, as Unix doesn't differentiate between text and binary. return std::error_code(); } @@ -497,4 +553,3 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, return true; } -} |