aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/Unix/Program.inc
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/Unix/Program.inc')
-rw-r--r--llvm/lib/Support/Unix/Program.inc87
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;
}
-}