diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index ed7481d886..81b56408ec 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -982,6 +982,7 @@ bool cmCTestBuildHandler::RunMakeCommand(const std::string& command, break; } } else { + chain.Terminate(); cmCTestOptionalLog(this->CTest, WARNING, "There was a timeout" << std::endl, this->Quiet); } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 1bed4f7aae..a475151760 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1179,6 +1179,7 @@ bool cmCTest::RunMakeCommand(const std::string& command, std::string& output, break; } } else { + chain.Terminate(); cmCTestLog(this, WARNING, "There was a timeout" << std::endl); } @@ -1351,6 +1352,8 @@ bool cmCTest::RunTest(const std::vector& argv, cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, outerr << std::endl); } break; } + } else { + chain.Terminate(); } return result; @@ -3611,6 +3614,7 @@ bool cmCTest::RunCommand(std::vector const& args, bool result = true; if (timedOut) { + chain.Terminate(); const char* error_str = "Process terminated due to timeout\n"; cmCTestLog(this, ERROR_MESSAGE, error_str << std::endl); stdErr->append(error_str, strlen(error_str)); diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 9b22d5620d..ed48a1787c 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -391,6 +391,9 @@ bool cmExecuteProcessCommand(std::vector const& args, !(chain.Finished() && outputData.Finished && errorData.Finished)) { uv_run(&chain.GetLoop(), UV_RUN_ONCE); } + if (timedOut) { + chain.Terminate(); + } if (!arguments.OutputQuiet && (arguments.OutputVariable.empty() || arguments.EchoOutputVariable)) { processOutput.DecodeText(std::string(), strdata, 1); diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index fc958b5aff..907c24d054 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -696,6 +696,7 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, bool result = true; if (timedOut) { + chain.Terminate(); const char* error_str = "Process terminated due to timeout\n"; if (outputflag != OUTPUT_NONE) { std::cerr << error_str << std::endl; diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index 4333e5fb07..f2a3cbe2cd 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -12,6 +12,8 @@ #include +#include "cmsys/Process.h" + #include "cm_fileno.hxx" #include "cmGetPipes.h" @@ -58,6 +60,7 @@ struct cmUVProcessChain::InternalData const cmUVProcessChainBuilder::ProcessConfiguration& config, bool first, bool last); void Finish(); + void Terminate(); }; cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default; @@ -388,6 +391,15 @@ void cmUVProcessChain::InternalData::Finish() this->Valid = true; } +void cmUVProcessChain::InternalData::Terminate() +{ + for (std::unique_ptr const& p : this->Processes) { + if (!p->ProcessStatus.Finished) { + cmsysProcess_KillPID(static_cast(p->Process->pid)); + } + } +} + cmUVProcessChain::cmUVProcessChain() : Data(cm::make_unique()) { @@ -472,6 +484,11 @@ bool cmUVProcessChain::Finished() const return this->Data->ProcessesCompleted >= this->Data->Processes.size(); } +void cmUVProcessChain::Terminate() +{ + this->Data->Terminate(); +} + std::pair cmUVProcessChain::Status::GetException() const { diff --git a/Source/cmUVProcessChain.h b/Source/cmUVProcessChain.h index 65816e2084..ac53bc3658 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -116,6 +116,10 @@ public: const Status& GetStatus(std::size_t index) const; bool Finished() const; + /** Terminate any remaining child processes. + Call this only after exiting the event loop, and at most once. */ + void Terminate(); + private: friend class cmUVProcessChainBuilder;