[llvm] eb93b87 - Support: Add polling option to sys::Wait
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 22 09:39:09 PST 2022
Author: Matt Arsenault
Date: 2022-12-22T12:38:59-05:00
New Revision: eb93b8774e2cfc5172f0727db8a50427adcb69d7
URL: https://github.com/llvm/llvm-project/commit/eb93b8774e2cfc5172f0727db8a50427adcb69d7
DIFF: https://github.com/llvm/llvm-project/commit/eb93b8774e2cfc5172f0727db8a50427adcb69d7.diff
LOG: Support: Add polling option to sys::Wait
Currently the process is terminated after the timeout. Add an option
to let the process resume after the timeout instead.
https://reviews.llvm.org/D138952
Added:
Modified:
llvm/include/llvm/Support/Program.h
llvm/lib/Support/Unix/Program.inc
llvm/lib/Support/Windows/Program.inc
llvm/unittests/Support/ProgramTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Support/Program.h b/llvm/include/llvm/Support/Program.h
index 79b038b8ebe7c..4c1133e44a21c 100644
--- a/llvm/include/llvm/Support/Program.h
+++ b/llvm/include/llvm/Support/Program.h
@@ -210,17 +210,22 @@ namespace sys {
std::optional<unsigned> SecondsToWait, ///< If std::nullopt, waits until
///< child has terminated.
///< If a value, this specifies the amount of time to wait for the child
- ///< process to exit. If the time expires, the child is killed and this
- ///< function returns. If zero, this function will perform a non-blocking
+ ///< process. If the time expires, and \p Polling is false, the child is
+ ///< killed and this < function returns. If the time expires and \p
+ ///< Polling is true, the child is resumed.
+ ///<
+ ///< If zero, this function will perform a non-blocking
///< wait on the child process.
std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a
///< string instance in which error messages will be returned. If the
///< string is non-empty upon return an error occurred while invoking the
///< program.
std::optional<ProcessStatistics> *ProcStat =
- nullptr ///< If non-zero, provides
+ nullptr, ///< If non-zero, provides
/// a pointer to a structure in which process execution statistics will
/// be stored.
+
+ bool Polling = false ///< If true, do not kill the process on timeout.
);
/// Print a command argument, and optionally quote it.
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index adfed226e6c1c..375102c080fdc 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -387,7 +387,8 @@ pid_t(llvm::sys::wait4)(pid_t pid, int *status, int options,
ProcessInfo llvm::sys::Wait(const ProcessInfo &PI,
std::optional<unsigned> SecondsToWait,
std::string *ErrMsg,
- std::optional<ProcessStatistics> *ProcStat) {
+ std::optional<ProcessStatistics> *ProcStat,
+ bool Polling) {
struct sigaction Act, Old;
assert(PI.Pid && "invalid pid to wait on, process not started?");
@@ -408,12 +409,11 @@ ProcessInfo llvm::sys::Wait(const ProcessInfo &PI,
sigemptyset(&Act.sa_mask);
sigaction(SIGALRM, &Act, &Old);
// FIXME The alarm signal may be delivered to another thread.
-
alarm(*SecondsToWait);
}
// Parent process: Wait for the child process to terminate.
- int status;
+ int status = 0;
ProcessInfo WaitResult;
rusage Info;
if (ProcStat)
@@ -428,7 +428,7 @@ ProcessInfo llvm::sys::Wait(const ProcessInfo &PI,
// Non-blocking wait.
return WaitResult;
} else {
- if (SecondsToWait && errno == EINTR) {
+ if (SecondsToWait && errno == EINTR && !Polling) {
// Kill the child.
kill(PI.Pid, SIGKILL);
diff --git a/llvm/lib/Support/Windows/Program.inc b/llvm/lib/Support/Windows/Program.inc
index 42f4efeb1ff10..0de9d3f756448 100644
--- a/llvm/lib/Support/Windows/Program.inc
+++ b/llvm/lib/Support/Windows/Program.inc
@@ -411,7 +411,8 @@ ErrorOr<std::wstring> sys::flattenWindowsCommandLine(ArrayRef<StringRef> Args) {
ProcessInfo sys::Wait(const ProcessInfo &PI,
std::optional<unsigned> SecondsToWait,
std::string *ErrMsg,
- std::optional<ProcessStatistics> *ProcStat) {
+ std::optional<ProcessStatistics> *ProcStat,
+ bool Polling) {
assert(PI.Pid && "invalid pid to wait on, process not started?");
assert((PI.Process && PI.Process != INVALID_HANDLE_VALUE) &&
"invalid process handle to wait on, process not started?");
@@ -422,7 +423,7 @@ ProcessInfo sys::Wait(const ProcessInfo &PI,
ProcStat->reset();
DWORD WaitStatus = WaitForSingleObject(PI.Process, milliSecondsToWait);
if (WaitStatus == WAIT_TIMEOUT) {
- if (*SecondsToWait > 0) {
+ if (!Polling && *SecondsToWait > 0) {
if (!TerminateProcess(PI.Process, 1)) {
if (ErrMsg)
MakeErrMsg(ErrMsg, "Failed to terminate timed-out program");
diff --git a/llvm/unittests/Support/ProgramTest.cpp b/llvm/unittests/Support/ProgramTest.cpp
index 0a09278716737..ca301dc3cc963 100644
--- a/llvm/unittests/Support/ProgramTest.cpp
+++ b/llvm/unittests/Support/ProgramTest.cpp
@@ -284,6 +284,45 @@ TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) {
ASSERT_EQ(-2, RetCode);
}
+TEST_F(ProgramEnvTest, TestExecuteNoWaitTimeoutPolling) {
+ using namespace llvm::sys;
+
+ if (getenv("LLVM_PROGRAM_TEST_TIMEOUT")) {
+ sleep_for(/*seconds*/ 5);
+ exit(0);
+ }
+
+ std::string Executable =
+ sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1);
+ StringRef argv[] = {
+ Executable,
+ "--gtest_filter=ProgramEnvTest.TestExecuteNoWaitTimeoutPolling"};
+
+ // Add LLVM_PROGRAM_TEST_TIMEOUT to the environment of the child.
+ addEnvVar("LLVM_PROGRAM_TEST_TIMEOUT=1");
+
+ std::string Error;
+ bool ExecutionFailed;
+ ProcessInfo PI0 = ExecuteNoWait(Executable, argv, getEnviron(),
+ /*Redirects=*/{}, /*MemoryLimit=*/0, &Error,
+ &ExecutionFailed);
+ ASSERT_FALSE(ExecutionFailed) << Error;
+ ASSERT_NE(PI0.Pid, ProcessInfo::InvalidPid) << "Invalid process id";
+
+ // Check that we don't kill the process with a non-0 SecondsToWait if Polling.
+ unsigned LoopCount = 0;
+ ProcessInfo WaitResult;
+ do {
+ ++LoopCount;
+ WaitResult = llvm::sys::Wait(PI0, /*SecondsToWait=*/1, &Error,
+ /*ProcStats=*/nullptr,
+ /*Polling=*/true);
+ ASSERT_TRUE(Error.empty()) << Error;
+ } while (WaitResult.Pid != PI0.Pid);
+
+ ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1";
+}
+
TEST(ProgramTest, TestExecuteNegative) {
std::string Executable = "i_dont_exist";
StringRef argv[] = {Executable};
More information about the llvm-commits
mailing list