diff --git a/Source/CTest/cmCTestBuildAndTest.cxx b/Source/CTest/cmCTestBuildAndTest.cxx index 68ca77a530..2e9d434576 100644 --- a/Source/CTest/cmCTestBuildAndTest.cxx +++ b/Source/CTest/cmCTestBuildAndTest.cxx @@ -122,6 +122,8 @@ bool cmCTestBuildAndTest::RunTest(std::vector const& argv, std::cout << "\n*** Exception executing: " << exception.second; } break; } + } else { + chain.Terminate(); } return result; diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 67e1af4a2d..f0e7dab326 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -1020,6 +1020,7 @@ bool cmCTestBuildHandler::RunMakeCommand(std::string const& 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 a2c5880bf1..e7d34fd308 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1004,6 +1004,7 @@ bool cmCTest::RunMakeCommand(std::string const& command, std::string& output, break; } } else { + chain.Terminate(); cmCTestLog(this, WARNING, "There was a timeout" << std::endl); } @@ -3372,6 +3373,7 @@ bool cmCTest::RunCommand(std::vector const& args, bool result = true; if (timedOut) { + chain.Terminate(); char const* 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 698a7fcce5..2c04d604ef 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -405,6 +405,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 0265a5b3f7..f6a0d10987 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -976,6 +976,7 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, bool result = true; if (timedOut) { + chain.Terminate(); char const* 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 deba10b653..8549037c28 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 cmUVProcessChainBuilder::ProcessConfiguration const& config, bool first, bool last); void Finish(); + void Terminate(); }; cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default; @@ -403,6 +406,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()) { @@ -487,6 +499,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 ae71010d9a..132c3a06cf 100644 --- a/Source/cmUVProcessChain.h +++ b/Source/cmUVProcessChain.h @@ -117,6 +117,10 @@ public: Status const& 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;