[Cmake-commits] CMake branch, master, updated. v3.10.1-799-g4cf08c9

Kitware Robot kwrobot at kitware.com
Thu Jan 11 15:35:10 EST 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  4cf08c96f8e6cba3af3b73d0e7317e2d1547a4c0 (commit)
       via  b5e21d7d2ed3168c9efcbc25c67d2c330d76d4d0 (commit)
       via  fcebff75f912f50bdc7fd30f4185141255ba4b1f (commit)
       via  3dd2edf4ab94f5044b73b20151592c8e94a5160a (commit)
       via  5238e6db70d275e42048479b737781fc97d82ea1 (commit)
       via  c13b68e61f3e89f9f52834c46a65fc7192ceb318 (commit)
       via  4d6b09037d8c640763504ad1378d42b12ef975aa (commit)
       via  05da65bc22dee788576504cdd203e5fdd5f9d633 (commit)
       via  dd945345715b90b2a1db769865c79d86a1dfad06 (commit)
       via  7e0eb77f2f0da764ba9d8a4045351bd7799e101d (commit)
       via  61ab5a8ef451484d3014118ed193eeba83bb22a4 (commit)
       via  4c199a4c28a0647c0277c7009b5f6e81b26333bb (commit)
       via  2567e5df69c1a4276c5e51dfa6c49482b24b1545 (commit)
       via  1138feb38f4e6d259ded23312b7f0f2184ac816a (commit)
       via  4ffb0f8b45a5abd51a04a399461c9096019a87f8 (commit)
      from  ae7c7b6db5d6765768e95485b2db1a1b18cfbded (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4cf08c96f8e6cba3af3b73d0e7317e2d1547a4c0
commit 4cf08c96f8e6cba3af3b73d0e7317e2d1547a4c0
Merge: ae7c7b6 b5e21d7
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jan 11 20:32:46 2018 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jan 11 15:33:03 2018 -0500

    Merge topic 'ctest-libuv'
    
    b5e21d7d CTest: Re-implement test process handling using libuv
    fcebff75 cmProcess: Use explicit enum for process exit exception
    3dd2edf4 cmProcess: Use explicit enum for process state
    5238e6db cmProcess: Remove unused ReportStatus method
    c13b68e6 cmCTestRunTest: Modernize constructor and destructor decls
    4d6b0903 cmCTestRunTest: Drop unused members
    05da65bc cmCTestMultiProcessHandler: Factor out duplicate test finish logic
    dd945345 cmCTestMultiProcessHandler: Add helper to make libuv use SA_RESTART
    ...
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Merge-request: !1455


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=b5e21d7d2ed3168c9efcbc25c67d2c330d76d4d0
commit b5e21d7d2ed3168c9efcbc25c67d2c330d76d4d0
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Sun Dec 10 12:06:35 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:14 2018 -0500

    CTest: Re-implement test process handling using libuv
    
    Co-Author: Brad King <brad.king at kitware.com>

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 453d5cb..53c47a2 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -9,9 +9,12 @@
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
+#include "cm_uv.h"
+
 #include "cmsys/FStream.hxx"
 #include "cmsys/String.hxx"
 #include "cmsys/SystemInformation.hxx"
+
 #include <algorithm>
 #include <chrono>
 #include <iomanip>
@@ -133,18 +136,16 @@ void cmCTestMultiProcessHandler::RunTests()
   if (this->HasCycles) {
     return;
   }
+#ifdef CMAKE_UV_SIGNAL_HACK
+  cmUVSignalHackRAII hackRAII;
+#endif
   this->TestHandler->SetMaxIndex(this->FindMaxIndex());
+
+  uv_loop_init(&this->Loop);
   this->StartNextTests();
-  while (!this->Tests.empty()) {
-    if (this->StopTimePassed) {
-      return;
-    }
-    this->CheckOutput();
-    this->StartNextTests();
-  }
-  // let all running tests finish
-  while (this->CheckOutput()) {
-  }
+  uv_run(&this->Loop, UV_RUN_DEFAULT);
+  uv_loop_close(&this->Loop);
+
   this->MarkFinished();
   this->UpdateCostData();
 }
@@ -168,7 +169,7 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test)
   this->EraseTest(test);
   this->RunningCount += GetProcessorsUsed(test);
 
-  cmCTestRunTest* testRun = new cmCTestRunTest(this->TestHandler);
+  cmCTestRunTest* testRun = new cmCTestRunTest(*this);
   if (this->CTest->GetRepeatUntilFail()) {
     testRun->SetRunUntilFailOn();
     testRun->SetNumberOfRuns(this->CTest->GetTestRepeat());
@@ -191,7 +192,6 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test)
   this->LockResources(test);
 
   if (testRun->StartTest(this->Total)) {
-    this->RunningTests.insert(testRun);
     return true;
   }
 
@@ -264,6 +264,11 @@ bool cmCTestMultiProcessHandler::StartTest(int test)
 void cmCTestMultiProcessHandler::StartNextTests()
 {
   size_t numToStart = 0;
+
+  if (this->Tests.empty()) {
+    return;
+  }
+
   if (this->RunningCount < this->ParallelLevel) {
     numToStart = this->ParallelLevel - this->RunningCount;
   }
@@ -396,25 +401,6 @@ void cmCTestMultiProcessHandler::StartNextTests()
   }
 }
 
-bool cmCTestMultiProcessHandler::CheckOutput()
-{
-  // no more output we are done
-  if (this->RunningTests.empty()) {
-    return false;
-  }
-  std::vector<cmCTestRunTest*> finished;
-  std::string out, err;
-  for (cmCTestRunTest* p : this->RunningTests) {
-    if (!p->CheckOutput()) {
-      finished.push_back(p);
-    }
-  }
-  for (cmCTestRunTest* p : finished) {
-    this->FinishTestProcess(p, true);
-  }
-  return true;
-}
-
 void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner,
                                                    bool started)
 {
@@ -429,7 +415,6 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner,
       this->Completed--; // remove the completed test because run again
       return;
     }
-    this->RunningTests.erase(runner);
   }
 
   if (testResult) {
@@ -449,6 +434,9 @@ void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner,
   this->RunningCount -= GetProcessorsUsed(test);
 
   delete runner;
+  if (started) {
+    this->StartNextTests();
+  }
 }
 
 void cmCTestMultiProcessHandler::UpdateCostData()
@@ -715,7 +703,7 @@ void cmCTestMultiProcessHandler::PrintTestList()
 
     cmWorkingDirectory workdir(p.Directory);
 
-    cmCTestRunTest testRun(this->TestHandler);
+    cmCTestRunTest testRun(*this);
     testRun.SetIndex(p.Index);
     testRun.SetTestProperties(&p);
     testRun.ComputeArguments(); // logs the command in verbose mode
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 80d6d4e..7837ff9 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -12,6 +12,8 @@
 #include <string>
 #include <vector>
 
+#include "cm_uv.h"
+
 class cmCTest;
 class cmCTestRunTest;
 
@@ -23,6 +25,7 @@ class cmCTestRunTest;
 class cmCTestMultiProcessHandler
 {
   friend class TestComparator;
+  friend class cmCTestRunTest;
 
 public:
   struct TestSet : public std::set<int>
@@ -95,9 +98,6 @@ protected:
   // Removes the checkpoint file
   void MarkFinished();
   void EraseTest(int index);
-  // Return true if there are still tests running
-  // check all running processes for output and exit case
-  bool CheckOutput();
   void FinishTestProcess(cmCTestRunTest* runner, bool started);
 
   void RemoveTest(int index);
@@ -132,7 +132,7 @@ protected:
   std::vector<cmCTestTestHandler::cmCTestTestResult>* TestResults;
   size_t ParallelLevel; // max number of process that can be run at once
   unsigned long TestLoad;
-  std::set<cmCTestRunTest*> RunningTests; // current running tests
+  uv_loop_t Loop;
   cmCTestTestHandler* TestHandler;
   cmCTest* CTest;
   bool HasCycles;
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 906e547..baf894e 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -4,27 +4,27 @@
 
 #include "cmCTest.h"
 #include "cmCTestMemCheckHandler.h"
-#include "cmCTestTestHandler.h"
+#include "cmCTestMultiProcessHandler.h"
 #include "cmProcess.h"
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
 #include "cm_zlib.h"
 #include "cmsys/Base64.h"
-#include "cmsys/Process.h"
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
+#include <cmAlgorithms.h>
 #include <iomanip>
 #include <ratio>
 #include <sstream>
 #include <stdio.h>
 #include <utility>
 
-cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
+cmCTestRunTest::cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler)
+  : MultiTestHandler(multiHandler)
 {
-  this->CTest = handler->CTest;
-  this->TestHandler = handler;
-  this->TestProcess = nullptr;
+  this->CTest = multiHandler.CTest;
+  this->TestHandler = multiHandler.TestHandler;
   this->TestResult.ExecutionTime = std::chrono::duration<double>::zero();
   this->TestResult.ReturnValue = 0;
   this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
@@ -38,50 +38,32 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
   this->RunAgain = false;     // default to not having to run again
 }
 
-bool cmCTestRunTest::CheckOutput()
+void cmCTestRunTest::CheckOutput(std::string const& line)
 {
-  // Read lines for up to 0.1 seconds of total time.
-  std::chrono::duration<double> timeout = std::chrono::milliseconds(100);
-  auto timeEnd = std::chrono::steady_clock::now() + timeout;
-  std::string line;
-  while ((timeout = timeEnd - std::chrono::steady_clock::now(),
-          timeout > std::chrono::seconds(0))) {
-    int p = this->TestProcess->GetNextOutputLine(line, timeout);
-    if (p == cmsysProcess_Pipe_None) {
-      // Process has terminated and all output read.
-      return false;
-    }
-    if (p == cmsysProcess_Pipe_STDOUT) {
-      // Store this line of output.
-      cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
-                   << ": " << line << std::endl);
-      this->ProcessOutput += line;
-      this->ProcessOutput += "\n";
-
-      // Check for TIMEOUT_AFTER_MATCH property.
-      if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
-        for (auto& reg : this->TestProperties->TimeoutRegularExpressions) {
-          if (reg.first.find(this->ProcessOutput.c_str())) {
-            cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
-                         << ": "
-                         << "Test timeout changed to "
-                         << std::chrono::duration_cast<std::chrono::seconds>(
-                              this->TestProperties->AlternateTimeout)
-                              .count()
-                         << std::endl);
-            this->TestProcess->ResetStartTime();
-            this->TestProcess->ChangeTimeout(
-              this->TestProperties->AlternateTimeout);
-            this->TestProperties->TimeoutRegularExpressions.clear();
-            break;
-          }
-        }
+  cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+               << ": " << line << std::endl);
+  this->ProcessOutput += line;
+  this->ProcessOutput += "\n";
+
+  // Check for TIMEOUT_AFTER_MATCH property.
+  if (!this->TestProperties->TimeoutRegularExpressions.empty()) {
+    for (auto& reg : this->TestProperties->TimeoutRegularExpressions) {
+      if (reg.first.find(this->ProcessOutput.c_str())) {
+        cmCTestLog(this->CTest, HANDLER_VERBOSE_OUTPUT, this->GetIndex()
+                     << ": "
+                     << "Test timeout changed to "
+                     << std::chrono::duration_cast<std::chrono::seconds>(
+                          this->TestProperties->AlternateTimeout)
+                          .count()
+                     << std::endl);
+        this->TestProcess->ResetStartTime();
+        this->TestProcess->ChangeTimeout(
+          this->TestProperties->AlternateTimeout);
+        this->TestProperties->TimeoutRegularExpressions.clear();
+        break;
       }
-    } else { // if(p == cmsysProcess_Pipe_Timeout)
-      break;
     }
   }
-  return true;
 }
 
 // Streamed compression of test output.  The compressed data
@@ -344,7 +326,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
   if (!this->NeedsToRerun()) {
     this->TestHandler->TestResults.push_back(this->TestResult);
   }
-  delete this->TestProcess;
+  this->TestProcess.reset();
   return passed || skipped;
 }
 
@@ -426,7 +408,7 @@ bool cmCTestRunTest::StartTest(size_t total)
     this->TestResult.TestCount = this->TestProperties->Index;
     this->TestResult.Name = this->TestProperties->Name;
     this->TestResult.Path = this->TestProperties->Directory;
-    this->TestProcess = new cmProcess;
+    this->TestProcess = cm::make_unique<cmProcess>(*this);
     this->TestResult.Output = "Disabled";
     this->TestResult.FullCommandLine.clear();
     return false;
@@ -447,7 +429,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   // its arguments are irrelevant. This matters for the case where a fixture
   // dependency might be creating the executable we want to run.
   if (!this->FailedDependencies.empty()) {
-    this->TestProcess = new cmProcess;
+    this->TestProcess = cm::make_unique<cmProcess>(*this);
     std::string msg = "Failed test dependencies:";
     for (std::string const& failedDep : this->FailedDependencies) {
       msg += " " + failedDep;
@@ -464,7 +446,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   this->ComputeArguments();
   std::vector<std::string>& args = this->TestProperties->Args;
   if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") {
-    this->TestProcess = new cmProcess;
+    this->TestProcess = cm::make_unique<cmProcess>(*this);
     std::string msg;
     if (this->CTest->GetConfigType().empty()) {
       msg = "Test not available without configuration.";
@@ -487,7 +469,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   for (std::string const& file : this->TestProperties->RequiredFiles) {
     if (!cmSystemTools::FileExists(file.c_str())) {
       // Required file was not found
-      this->TestProcess = new cmProcess;
+      this->TestProcess = cm::make_unique<cmProcess>(*this);
       *this->TestHandler->LogFile << "Unable to find required file: " << file
                                   << std::endl;
       cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -503,7 +485,7 @@ bool cmCTestRunTest::StartTest(size_t total)
   if (this->ActualCommand.empty()) {
     // if the command was not found create a TestResult object
     // that has that information
-    this->TestProcess = new cmProcess;
+    this->TestProcess = cm::make_unique<cmProcess>(*this);
     *this->TestHandler->LogFile << "Unable to find executable: " << args[1]
                                 << std::endl;
     cmCTestLog(this->CTest, ERROR_MESSAGE,
@@ -612,7 +594,7 @@ bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
                                  bool explicitTimeout,
                                  std::vector<std::string>* environment)
 {
-  this->TestProcess = new cmProcess;
+  this->TestProcess = cm::make_unique<cmProcess>(*this);
   this->TestProcess->SetId(this->Index);
   this->TestProcess->SetWorkingDirectory(
     this->TestProperties->Directory.c_str());
@@ -664,7 +646,7 @@ bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
     cmSystemTools::AppendEnv(*environment);
   }
 
-  return this->TestProcess->StartProcess();
+  return this->TestProcess->StartProcess(this->MultiTestHandler.Loop);
 }
 
 void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
@@ -738,3 +720,8 @@ void cmCTestRunTest::WriteLogOutputTop(size_t completed, size_t total)
   cmCTestLog(this->CTest, DEBUG, "Testing " << this->TestProperties->Name
                                             << " ... ");
 }
+
+void cmCTestRunTest::FinalizeTest()
+{
+  this->MultiTestHandler.FinishTestProcess(this, true);
+}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index bde93da..fbc202f 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -12,9 +12,10 @@
 #include <vector>
 
 #include "cmCTestTestHandler.h"
+#include "cmProcess.h" // IWYU pragma: keep (for unique_ptr)
 
 class cmCTest;
-class cmProcess;
+class cmCTestMultiProcessHandler;
 
 /** \class cmRunTest
  * \brief represents a single test to be run
@@ -24,7 +25,7 @@ class cmProcess;
 class cmCTestRunTest
 {
 public:
-  explicit cmCTestRunTest(cmCTestTestHandler* handler);
+  explicit cmCTestRunTest(cmCTestMultiProcessHandler& multiHandler);
 
   ~cmCTestRunTest() = default;
 
@@ -57,7 +58,7 @@ public:
   }
 
   // Read and store output.  Returns true if it must be called again.
-  bool CheckOutput();
+  void CheckOutput(std::string const& line);
 
   // Compresses the output, writing to CompressedOutput
   void CompressOutput();
@@ -73,6 +74,10 @@ public:
 
   bool StartAgain();
 
+  cmCTest* GetCTest() const { return this->CTest; }
+
+  void FinalizeTest();
+
 private:
   bool NeedsToRerun();
   void DartProcessing();
@@ -88,12 +93,13 @@ private:
   // Pointer back to the "parent"; the handler that invoked this test run
   cmCTestTestHandler* TestHandler;
   cmCTest* CTest;
-  cmProcess* TestProcess;
+  std::unique_ptr<cmProcess> TestProcess;
   std::string ProcessOutput;
   std::string CompressedOutput;
   double CompressionRatio;
   // The test results
   cmCTestTestHandler::cmCTestTestResult TestResult;
+  cmCTestMultiProcessHandler& MultiTestHandler;
   int Index;
   std::set<std::string> FailedDependencies;
   std::string StartTime;
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 857f5c1..c8806a7 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -2,11 +2,65 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmProcess.h"
 
+#include "cmCTest.h"
+#include "cmCTestRunTest.h"
+#include "cmCTestTestHandler.h"
 #include "cmProcessOutput.h"
+#include "cmsys/Process.h"
 
-cmProcess::cmProcess()
+#include <algorithm>
+#include <fcntl.h>
+#include <iostream>
+#include <signal.h>
+#include <stdint.h>
+#include <string>
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h>
+
+static int cmProcessGetPipes(int* fds)
+{
+  SECURITY_ATTRIBUTES attr;
+  HANDLE readh, writeh;
+  attr.nLength = sizeof(attr);
+  attr.lpSecurityDescriptor = nullptr;
+  attr.bInheritHandle = FALSE;
+  if (!CreatePipe(&readh, &writeh, &attr, 0))
+    return uv_translate_sys_error(GetLastError());
+  fds[0] = _open_osfhandle((intptr_t)readh, 0);
+  fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+  if (fds[0] == -1 || fds[1] == -1) {
+    CloseHandle(readh);
+    CloseHandle(writeh);
+    return uv_translate_sys_error(GetLastError());
+  }
+  return 0;
+}
+#else
+#include <errno.h>
+
+static int cmProcessGetPipes(int* fds)
+{
+  if (pipe(fds) == -1) {
+    return uv_translate_sys_error(errno);
+  }
+
+  if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+      fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+    close(fds[0]);
+    close(fds[1]);
+    return uv_translate_sys_error(errno);
+  }
+  return 0;
+}
+#endif
+
+cmProcess::cmProcess(cmCTestRunTest& runner)
+  : Runner(runner)
 {
-  this->Process = nullptr;
   this->Timeout = std::chrono::duration<double>::zero();
   this->TotalTime = std::chrono::duration<double>::zero();
   this->ExitValue = 0;
@@ -16,8 +70,8 @@ cmProcess::cmProcess()
 
 cmProcess::~cmProcess()
 {
-  cmsysProcess_Delete(this->Process);
 }
+
 void cmProcess::SetCommand(const char* command)
 {
   this->Command = command;
@@ -28,8 +82,9 @@ void cmProcess::SetCommandArguments(std::vector<std::string> const& args)
   this->Arguments = args;
 }
 
-bool cmProcess::StartProcess()
+bool cmProcess::StartProcess(uv_loop_t& loop)
 {
+  this->ProcessState = cmProcess::State::Error;
   if (this->Command.empty()) {
     return false;
   }
@@ -42,17 +97,83 @@ bool cmProcess::StartProcess()
     this->ProcessArgs.push_back(arg.c_str());
   }
   this->ProcessArgs.push_back(nullptr); // null terminate the list
-  this->Process = cmsysProcess_New();
-  cmsysProcess_SetCommand(this->Process, &*this->ProcessArgs.begin());
-  if (!this->WorkingDirectory.empty()) {
-    cmsysProcess_SetWorkingDirectory(this->Process,
-                                     this->WorkingDirectory.c_str());
+
+  cm::uv_timer_ptr timer;
+  int status = timer.init(loop, this);
+  if (status != 0) {
+    cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
+               "Error initializing timer: " << uv_strerror(status)
+                                            << std::endl);
+    return false;
+  }
+
+  cm::uv_pipe_ptr pipe_writer;
+  cm::uv_pipe_ptr pipe_reader;
+
+  pipe_writer.init(loop, 0);
+  pipe_reader.init(loop, 0, this);
+
+  int fds[2] = { -1, -1 };
+  status = cmProcessGetPipes(fds);
+  if (status != 0) {
+    cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
+               "Error initializing pipe: " << uv_strerror(status)
+                                           << std::endl);
+    return false;
+  }
+
+  uv_pipe_open(pipe_reader, fds[0]);
+  uv_pipe_open(pipe_writer, fds[1]);
+
+  uv_stdio_container_t stdio[3];
+  stdio[0].flags = UV_IGNORE;
+  stdio[1].flags = UV_INHERIT_STREAM;
+  stdio[1].data.stream = pipe_writer;
+  stdio[2] = stdio[1];
+
+  uv_process_options_t options = uv_process_options_t();
+  options.file = this->Command.data();
+  options.args = const_cast<char**>(this->ProcessArgs.data());
+  options.stdio_count = 3; // in, out and err
+  options.exit_cb = &cmProcess::OnExitCB;
+  options.stdio = stdio;
+
+  status =
+    uv_read_start(pipe_reader, &cmProcess::OnAllocateCB, &cmProcess::OnReadCB);
+
+  if (status != 0) {
+    cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
+               "Error starting read events: " << uv_strerror(status)
+                                              << std::endl);
+    return false;
+  }
+
+  status = this->Process.spawn(loop, options, this);
+  if (status != 0) {
+    cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE, "Process not started\n "
+                 << this->Command << "\n[" << uv_strerror(status) << "]\n");
+    return false;
+  }
+
+  this->PipeReader = std::move(pipe_reader);
+  this->Timer = std::move(timer);
+
+  this->StartTimer();
+
+  this->ProcessState = cmProcess::State::Executing;
+  return true;
+}
+
+void cmProcess::StartTimer()
+{
+  auto properties = this->Runner.GetTestProperties();
+  auto msec =
+    std::chrono::duration_cast<std::chrono::milliseconds>(this->Timeout);
+
+  if (msec != std::chrono::milliseconds(0) || !properties->ExplicitTimeout) {
+    this->Timer.start(&cmProcess::OnTimeoutCB,
+                      static_cast<uint64_t>(msec.count()), 0);
   }
-  cmsysProcess_SetTimeout(this->Process, this->Timeout.count());
-  cmsysProcess_SetOption(this->Process, cmsysProcess_Option_MergeOutput, 1);
-  cmsysProcess_Execute(this->Process);
-  return (cmsysProcess_GetState(this->Process) ==
-          cmsysProcess_State_Executing);
 }
 
 bool cmProcess::Buffer::GetLine(std::string& line)
@@ -99,51 +220,121 @@ bool cmProcess::Buffer::GetLast(std::string& line)
   return false;
 }
 
-int cmProcess::GetNextOutputLine(std::string& line,
-                                 std::chrono::duration<double> timeout)
+void cmProcess::OnReadCB(uv_stream_t* stream, ssize_t nread,
+                         const uv_buf_t* buf)
 {
-  cmProcessOutput processOutput(cmProcessOutput::UTF8);
-  std::string strdata;
-  double waitTimeout = timeout.count();
-  for (;;) {
-    // Look for lines already buffered.
-    if (this->Output.GetLine(line)) {
-      return cmsysProcess_Pipe_STDOUT;
-    }
+  auto self = static_cast<cmProcess*>(stream->data);
+  self->OnRead(nread, buf);
+}
 
-    // Check for more data from the process.
-    char* data;
-    int length;
-    int p =
-      cmsysProcess_WaitForData(this->Process, &data, &length, &waitTimeout);
-    if (p == cmsysProcess_Pipe_Timeout) {
-      return cmsysProcess_Pipe_Timeout;
-    }
-    if (p == cmsysProcess_Pipe_STDOUT) {
-      processOutput.DecodeText(data, length, strdata);
-      this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
-    } else { // p == cmsysProcess_Pipe_None
-      // The process will provide no more data.
-      break;
+void cmProcess::OnRead(ssize_t nread, const uv_buf_t* buf)
+{
+  std::string line;
+  if (nread > 0) {
+    std::string strdata;
+    cmProcessOutput processOutput(cmProcessOutput::UTF8,
+                                  static_cast<unsigned int>(buf->len));
+    processOutput.DecodeText(buf->base, static_cast<size_t>(nread), strdata);
+    this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+
+    while (this->Output.GetLine(line)) {
+      this->Runner.CheckOutput(line);
+      line.clear();
     }
+
+    return;
   }
-  processOutput.DecodeText(std::string(), strdata);
-  if (!strdata.empty()) {
-    this->Output.insert(this->Output.end(), strdata.begin(), strdata.end());
+
+  // The process will provide no more data.
+  if (nread != UV_EOF) {
+    auto error = static_cast<int>(nread);
+    cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
+               "Error reading stream: " << uv_strerror(error) << std::endl);
   }
 
   // Look for partial last lines.
   if (this->Output.GetLast(line)) {
-    return cmsysProcess_Pipe_STDOUT;
+    this->Runner.CheckOutput(line);
+  }
+
+  this->ReadHandleClosed = true;
+  if (this->ProcessHandleClosed) {
+    uv_timer_stop(this->Timer);
+    this->Runner.FinalizeTest();
+  }
+}
+
+void cmProcess::OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
+                             uv_buf_t* buf)
+{
+  auto self = static_cast<cmProcess*>(handle->data);
+  self->OnAllocate(suggested_size, buf);
+}
+
+void cmProcess::OnAllocate(size_t suggested_size, uv_buf_t* buf)
+{
+  if (this->Buf.size() < suggested_size) {
+    this->Buf.resize(suggested_size);
+  }
+
+  *buf =
+    uv_buf_init(this->Buf.data(), static_cast<unsigned int>(this->Buf.size()));
+}
+
+void cmProcess::OnTimeoutCB(uv_timer_t* timer)
+{
+  auto self = static_cast<cmProcess*>(timer->data);
+  self->OnTimeout();
+}
+
+void cmProcess::OnTimeout()
+{
+  if (this->ProcessState != cmProcess::State::Executing) {
+    return;
+  }
+  this->ProcessState = cmProcess::State::Expired;
+  bool const was_still_reading = !this->ReadHandleClosed;
+  if (!this->ReadHandleClosed) {
+    this->ReadHandleClosed = true;
+    this->PipeReader.reset();
   }
+  if (!this->ProcessHandleClosed) {
+    // Kill the child and let our on-exit handler finish the test.
+    cmsysProcess_KillPID(static_cast<unsigned long>(this->Process->pid));
+  } else if (was_still_reading) {
+    // Our on-exit handler already ran but did not finish the test
+    // because we were still reading output.  We've just dropped
+    // our read handler, so we need to finish the test now.
+    this->Runner.FinalizeTest();
+  }
+}
 
-  // No more data.  Wait for process exit.
-  if (!cmsysProcess_WaitForExit(this->Process, &waitTimeout)) {
-    return cmsysProcess_Pipe_Timeout;
+void cmProcess::OnExitCB(uv_process_t* process, int64_t exit_status,
+                         int term_signal)
+{
+  auto self = static_cast<cmProcess*>(process->data);
+  self->OnExit(exit_status, term_signal);
+}
+
+void cmProcess::OnExit(int64_t exit_status, int term_signal)
+{
+  if (this->ProcessState != cmProcess::State::Expired) {
+    if (
+#if defined(_WIN32)
+      ((DWORD)exit_status & 0xF0000000) == 0xC0000000
+#else
+      term_signal != 0
+#endif
+      ) {
+      this->ProcessState = cmProcess::State::Exception;
+    } else {
+      this->ProcessState = cmProcess::State::Exited;
+    }
   }
 
   // Record exit information.
-  this->ExitValue = cmsysProcess_GetExitValue(this->Process);
+  this->ExitValue = static_cast<int>(exit_status);
+  this->Signal = term_signal;
   this->TotalTime = std::chrono::steady_clock::now() - this->StartTime;
   // Because of a processor clock scew the runtime may become slightly
   // negative. If someone changed the system clock while the process was
@@ -152,67 +343,373 @@ int cmProcess::GetNextOutputLine(std::string& line,
   if (this->TotalTime <= std::chrono::duration<double>::zero()) {
     this->TotalTime = std::chrono::duration<double>::zero();
   }
-  //  std::cerr << "Time to run: " << this->TotalTime << "\n";
-  return cmsysProcess_Pipe_None;
+
+  this->ProcessHandleClosed = true;
+  if (this->ReadHandleClosed) {
+    uv_timer_stop(this->Timer);
+    this->Runner.FinalizeTest();
+  }
 }
 
 cmProcess::State cmProcess::GetProcessStatus()
 {
-  if (this->Process) {
-    switch (cmsysProcess_GetState(this->Process)) {
-      case cmsysProcess_State_Starting:
-        return State::Starting;
-      case cmsysProcess_State_Error:
-        return State::Error;
-      case cmsysProcess_State_Exception:
-        return State::Exception;
-      case cmsysProcess_State_Executing:
-        return State::Executing;
-      case cmsysProcess_State_Expired:
-        return State::Expired;
-      case cmsysProcess_State_Killed:
-        return State::Killed;
-      case cmsysProcess_State_Disowned:
-        return State::Disowned;
-      default: // case cmsysProcess_State_Exited:
-        break;
-    }
-  }
-  return State::Exited;
+  return this->ProcessState;
 }
 
 void cmProcess::ChangeTimeout(std::chrono::duration<double> t)
 {
   this->Timeout = t;
-  cmsysProcess_SetTimeout(this->Process, this->Timeout.count());
+  this->StartTimer();
 }
 
 void cmProcess::ResetStartTime()
 {
-  cmsysProcess_ResetStartTime(this->Process);
   this->StartTime = std::chrono::steady_clock::now();
 }
 
 cmProcess::Exception cmProcess::GetExitException()
 {
-  switch (cmsysProcess_GetExitException(this->Process)) {
-    case cmsysProcess_Exception_None:
-      return Exception::None;
-    case cmsysProcess_Exception_Fault:
-      return Exception::Fault;
-    case cmsysProcess_Exception_Illegal:
-      return Exception::Illegal;
-    case cmsysProcess_Exception_Interrupt:
-      return Exception::Interrupt;
-    case cmsysProcess_Exception_Numerical:
-      return Exception::Numerical;
-    default: // case cmsysProcess_Exception_Other:
-      break;
+  auto exception = Exception::None;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  auto exit_code = (DWORD) this->ExitValue;
+  if ((exit_code & 0xF0000000) != 0xC0000000) {
+    return exception;
+  }
+
+  if (exit_code) {
+    switch (exit_code) {
+      case STATUS_DATATYPE_MISALIGNMENT:
+      case STATUS_ACCESS_VIOLATION:
+      case STATUS_IN_PAGE_ERROR:
+      case STATUS_INVALID_HANDLE:
+      case STATUS_NONCONTINUABLE_EXCEPTION:
+      case STATUS_INVALID_DISPOSITION:
+      case STATUS_ARRAY_BOUNDS_EXCEEDED:
+      case STATUS_STACK_OVERFLOW:
+        exception = Exception::Fault;
+        break;
+      case STATUS_FLOAT_DENORMAL_OPERAND:
+      case STATUS_FLOAT_DIVIDE_BY_ZERO:
+      case STATUS_FLOAT_INEXACT_RESULT:
+      case STATUS_FLOAT_INVALID_OPERATION:
+      case STATUS_FLOAT_OVERFLOW:
+      case STATUS_FLOAT_STACK_CHECK:
+      case STATUS_FLOAT_UNDERFLOW:
+#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+      case STATUS_FLOAT_MULTIPLE_FAULTS:
+#endif
+#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+      case STATUS_FLOAT_MULTIPLE_TRAPS:
+#endif
+      case STATUS_INTEGER_DIVIDE_BY_ZERO:
+      case STATUS_INTEGER_OVERFLOW:
+        exception = Exception::Numerical;
+        break;
+      case STATUS_CONTROL_C_EXIT:
+        exception = Exception::Interrupt;
+        break;
+      case STATUS_ILLEGAL_INSTRUCTION:
+      case STATUS_PRIVILEGED_INSTRUCTION:
+        exception = Exception::Illegal;
+        break;
+      default:
+        exception = Exception::Other;
+    }
   }
-  return Exception::Other;
+#else
+  if (this->Signal) {
+    switch (this->Signal) {
+      case SIGSEGV:
+        exception = Exception::Fault;
+        break;
+      case SIGFPE:
+        exception = Exception::Numerical;
+        break;
+      case SIGINT:
+        exception = Exception::Interrupt;
+        break;
+      case SIGILL:
+        exception = Exception::Illegal;
+        break;
+      default:
+        exception = Exception::Other;
+    }
+  }
+#endif
+  return exception;
 }
 
 std::string cmProcess::GetExitExceptionString()
 {
-  return cmsysProcess_GetExceptionString(this->Process);
+  std::string exception_str;
+#if defined(_WIN32)
+  switch (this->ExitValue) {
+    case STATUS_CONTROL_C_EXIT:
+      exception_str = "User interrupt";
+      break;
+    case STATUS_FLOAT_DENORMAL_OPERAND:
+      exception_str = "Floating-point exception (denormal operand)";
+      break;
+    case STATUS_FLOAT_DIVIDE_BY_ZERO:
+      exception_str = "Divide-by-zero";
+      break;
+    case STATUS_FLOAT_INEXACT_RESULT:
+      exception_str = "Floating-point exception (inexact result)";
+      break;
+    case STATUS_FLOAT_INVALID_OPERATION:
+      exception_str = "Invalid floating-point operation";
+      break;
+    case STATUS_FLOAT_OVERFLOW:
+      exception_str = "Floating-point overflow";
+      break;
+    case STATUS_FLOAT_STACK_CHECK:
+      exception_str = "Floating-point stack check failed";
+      break;
+    case STATUS_FLOAT_UNDERFLOW:
+      exception_str = "Floating-point underflow";
+      break;
+#ifdef STATUS_FLOAT_MULTIPLE_FAULTS
+    case STATUS_FLOAT_MULTIPLE_FAULTS:
+      exception_str = "Floating-point exception (multiple faults)";
+      break;
+#endif
+#ifdef STATUS_FLOAT_MULTIPLE_TRAPS
+    case STATUS_FLOAT_MULTIPLE_TRAPS:
+      exception_str = "Floating-point exception (multiple traps)";
+      break;
+#endif
+    case STATUS_INTEGER_DIVIDE_BY_ZERO:
+      exception_str = "Integer divide-by-zero";
+      break;
+    case STATUS_INTEGER_OVERFLOW:
+      exception_str = "Integer overflow";
+      break;
+
+    case STATUS_DATATYPE_MISALIGNMENT:
+      exception_str = "Datatype misalignment";
+      break;
+    case STATUS_ACCESS_VIOLATION:
+      exception_str = "Access violation";
+      break;
+    case STATUS_IN_PAGE_ERROR:
+      exception_str = "In-page error";
+      break;
+    case STATUS_INVALID_HANDLE:
+      exception_str = "Invalid handle";
+      break;
+    case STATUS_NONCONTINUABLE_EXCEPTION:
+      exception_str = "Noncontinuable exception";
+      break;
+    case STATUS_INVALID_DISPOSITION:
+      exception_str = "Invalid disposition";
+      break;
+    case STATUS_ARRAY_BOUNDS_EXCEEDED:
+      exception_str = "Array bounds exceeded";
+      break;
+    case STATUS_STACK_OVERFLOW:
+      exception_str = "Stack overflow";
+      break;
+
+    case STATUS_ILLEGAL_INSTRUCTION:
+      exception_str = "Illegal instruction";
+      break;
+    case STATUS_PRIVILEGED_INSTRUCTION:
+      exception_str = "Privileged instruction";
+      break;
+    case STATUS_NO_MEMORY:
+    default:
+      char buf[1024];
+      _snprintf(buf, 1024, "Exit code 0x%x\n", this->ExitValue);
+      exception_str.assign(buf);
+  }
+#else
+  switch (this->Signal) {
+#ifdef SIGSEGV
+    case SIGSEGV:
+      exception_str = "Segmentation fault";
+      break;
+#endif
+#ifdef SIGBUS
+#if !defined(SIGSEGV) || SIGBUS != SIGSEGV
+    case SIGBUS:
+      exception_str = "Bus error";
+      break;
+#endif
+#endif
+#ifdef SIGFPE
+    case SIGFPE:
+      exception_str = "Floating-point exception";
+      break;
+#endif
+#ifdef SIGILL
+    case SIGILL:
+      exception_str = "Illegal instruction";
+      break;
+#endif
+#ifdef SIGINT
+    case SIGINT:
+      exception_str = "User interrupt";
+      break;
+#endif
+#ifdef SIGABRT
+    case SIGABRT:
+      exception_str = "Child aborted";
+      break;
+#endif
+#ifdef SIGKILL
+    case SIGKILL:
+      exception_str = "Child killed";
+      break;
+#endif
+#ifdef SIGTERM
+    case SIGTERM:
+      exception_str = "Child terminated";
+      break;
+#endif
+#ifdef SIGHUP
+    case SIGHUP:
+      exception_str = "SIGHUP";
+      break;
+#endif
+#ifdef SIGQUIT
+    case SIGQUIT:
+      exception_str = "SIGQUIT";
+      break;
+#endif
+#ifdef SIGTRAP
+    case SIGTRAP:
+      exception_str = "SIGTRAP";
+      break;
+#endif
+#ifdef SIGIOT
+#if !defined(SIGABRT) || SIGIOT != SIGABRT
+    case SIGIOT:
+      exception_str = "SIGIOT";
+      break;
+#endif
+#endif
+#ifdef SIGUSR1
+    case SIGUSR1:
+      exception_str = "SIGUSR1";
+      break;
+#endif
+#ifdef SIGUSR2
+    case SIGUSR2:
+      exception_str = "SIGUSR2";
+      break;
+#endif
+#ifdef SIGPIPE
+    case SIGPIPE:
+      exception_str = "SIGPIPE";
+      break;
+#endif
+#ifdef SIGALRM
+    case SIGALRM:
+      exception_str = "SIGALRM";
+      break;
+#endif
+#ifdef SIGSTKFLT
+    case SIGSTKFLT:
+      exception_str = "SIGSTKFLT";
+      break;
+#endif
+#ifdef SIGCHLD
+    case SIGCHLD:
+      exception_str = "SIGCHLD";
+      break;
+#elif defined(SIGCLD)
+    case SIGCLD:
+      exception_str = "SIGCLD";
+      break;
+#endif
+#ifdef SIGCONT
+    case SIGCONT:
+      exception_str = "SIGCONT";
+      break;
+#endif
+#ifdef SIGSTOP
+    case SIGSTOP:
+      exception_str = "SIGSTOP";
+      break;
+#endif
+#ifdef SIGTSTP
+    case SIGTSTP:
+      exception_str = "SIGTSTP";
+      break;
+#endif
+#ifdef SIGTTIN
+    case SIGTTIN:
+      exception_str = "SIGTTIN";
+      break;
+#endif
+#ifdef SIGTTOU
+    case SIGTTOU:
+      exception_str = "SIGTTOU";
+      break;
+#endif
+#ifdef SIGURG
+    case SIGURG:
+      exception_str = "SIGURG";
+      break;
+#endif
+#ifdef SIGXCPU
+    case SIGXCPU:
+      exception_str = "SIGXCPU";
+      break;
+#endif
+#ifdef SIGXFSZ
+    case SIGXFSZ:
+      exception_str = "SIGXFSZ";
+      break;
+#endif
+#ifdef SIGVTALRM
+    case SIGVTALRM:
+      exception_str = "SIGVTALRM";
+      break;
+#endif
+#ifdef SIGPROF
+    case SIGPROF:
+      exception_str = "SIGPROF";
+      break;
+#endif
+#ifdef SIGWINCH
+    case SIGWINCH:
+      exception_str = "SIGWINCH";
+      break;
+#endif
+#ifdef SIGPOLL
+    case SIGPOLL:
+      exception_str = "SIGPOLL";
+      break;
+#endif
+#ifdef SIGIO
+#if !defined(SIGPOLL) || SIGIO != SIGPOLL
+    case SIGIO:
+      exception_str = "SIGIO";
+      break;
+#endif
+#endif
+#ifdef SIGPWR
+    case SIGPWR:
+      exception_str = "SIGPWR";
+      break;
+#endif
+#ifdef SIGSYS
+    case SIGSYS:
+      exception_str = "SIGSYS";
+      break;
+#endif
+#ifdef SIGUNUSED
+#if !defined(SIGSYS) || SIGUNUSED != SIGSYS
+    case SIGUNUSED:
+      exception_str = "SIGUNUSED";
+      break;
+#endif
+#endif
+    default:
+      exception_str = "Signal ";
+      exception_str += std::to_string(this->Signal);
+  }
+#endif
+  return exception_str;
 }
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 297cc47..9250896 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -5,11 +5,17 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
-#include "cmsys/Process.h"
+#include "cmUVHandlePtr.h"
+#include "cm_uv.h"
+
 #include <chrono>
+#include <stddef.h>
 #include <string>
+#include <sys/types.h>
 #include <vector>
 
+class cmCTestRunTest;
+
 /** \class cmProcess
  * \brief run a process with c++
  *
@@ -18,7 +24,7 @@
 class cmProcess
 {
 public:
-  cmProcess();
+  explicit cmProcess(cmCTestRunTest& runner);
   ~cmProcess();
   const char* GetCommand() { return this->Command.c_str(); }
   void SetCommand(const char* command);
@@ -28,7 +34,7 @@ public:
   void ChangeTimeout(std::chrono::duration<double> t);
   void ResetStartTime();
   // Return true if the process starts
-  bool StartProcess();
+  bool StartProcess(uv_loop_t& loop);
 
   enum class State
   {
@@ -61,21 +67,37 @@ public:
   Exception GetExitException();
   std::string GetExitExceptionString();
 
-  /**
-   * Read one line of output but block for no more than timeout.
-   * Returns:
-   *   cmsysProcess_Pipe_None    = Process terminated and all output read
-   *   cmsysProcess_Pipe_STDOUT  = Line came from stdout or stderr
-   *   cmsysProcess_Pipe_Timeout = Timeout expired while waiting
-   */
-  int GetNextOutputLine(std::string& line,
-                        std::chrono::duration<double> timeout);
-
 private:
   std::chrono::duration<double> Timeout;
   std::chrono::steady_clock::time_point StartTime;
   std::chrono::duration<double> TotalTime;
-  cmsysProcess* Process;
+  bool ReadHandleClosed = false;
+  bool ProcessHandleClosed = false;
+
+  cm::uv_process_ptr Process;
+  cm::uv_pipe_ptr PipeReader;
+  cm::uv_timer_ptr Timer;
+  std::vector<char> Buf;
+
+  cmCTestRunTest& Runner;
+  int Signal = 0;
+  cmProcess::State ProcessState = cmProcess::State::Starting;
+
+  static void OnExitCB(uv_process_t* process, int64_t exit_status,
+                       int term_signal);
+  static void OnTimeoutCB(uv_timer_t* timer);
+  static void OnReadCB(uv_stream_t* stream, ssize_t nread,
+                       const uv_buf_t* buf);
+  static void OnAllocateCB(uv_handle_t* handle, size_t suggested_size,
+                           uv_buf_t* buf);
+
+  void OnExit(int64_t exit_status, int term_signal);
+  void OnTimeout();
+  void OnRead(ssize_t nread, const uv_buf_t* buf);
+  void OnAllocate(size_t suggested_size, uv_buf_t* buf);
+
+  void StartTimer();
+
   class Buffer : public std::vector<char>
   {
     // Half-open index range of partial line already scanned.

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=fcebff75f912f50bdc7fd30f4185141255ba4b1f
commit fcebff75f912f50bdc7fd30f4185141255ba4b1f
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:14 2018 -0500

    cmProcess: Use explicit enum for process exit exception
    
    Translate the values from KWSys Process.

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 1f7516c..906e547 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -225,19 +225,19 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
     this->TestResult.ExceptionStatus =
       this->TestProcess->GetExitExceptionString();
     switch (this->TestProcess->GetExitException()) {
-      case cmsysProcess_Exception_Fault:
+      case cmProcess::Exception::Fault:
         cmCTestLog(this->CTest, HANDLER_OUTPUT, "SegFault");
         this->TestResult.Status = cmCTestTestHandler::SEGFAULT;
         break;
-      case cmsysProcess_Exception_Illegal:
+      case cmProcess::Exception::Illegal:
         cmCTestLog(this->CTest, HANDLER_OUTPUT, "Illegal");
         this->TestResult.Status = cmCTestTestHandler::ILLEGAL;
         break;
-      case cmsysProcess_Exception_Interrupt:
+      case cmProcess::Exception::Interrupt:
         cmCTestLog(this->CTest, HANDLER_OUTPUT, "Interrupt");
         this->TestResult.Status = cmCTestTestHandler::INTERRUPT;
         break;
-      case cmsysProcess_Exception_Numerical:
+      case cmProcess::Exception::Numerical:
         cmCTestLog(this->CTest, HANDLER_OUTPUT, "Numerical");
         this->TestResult.Status = cmCTestTestHandler::NUMERICAL;
         break;
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index fac0df9..857f5c1 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -193,9 +193,23 @@ void cmProcess::ResetStartTime()
   this->StartTime = std::chrono::steady_clock::now();
 }
 
-int cmProcess::GetExitException()
+cmProcess::Exception cmProcess::GetExitException()
 {
-  return cmsysProcess_GetExitException(this->Process);
+  switch (cmsysProcess_GetExitException(this->Process)) {
+    case cmsysProcess_Exception_None:
+      return Exception::None;
+    case cmsysProcess_Exception_Fault:
+      return Exception::Fault;
+    case cmsysProcess_Exception_Illegal:
+      return Exception::Illegal;
+    case cmsysProcess_Exception_Interrupt:
+      return Exception::Interrupt;
+    case cmsysProcess_Exception_Numerical:
+      return Exception::Numerical;
+    default: // case cmsysProcess_Exception_Other:
+      break;
+  }
+  return Exception::Other;
 }
 
 std::string cmProcess::GetExitExceptionString()
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 79379aa..297cc47 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -47,8 +47,20 @@ public:
   void SetId(int id) { this->Id = id; }
   int GetExitValue() { return this->ExitValue; }
   std::chrono::duration<double> GetTotalTime() { return this->TotalTime; }
-  int GetExitException();
+
+  enum class Exception
+  {
+    None,
+    Fault,
+    Illegal,
+    Interrupt,
+    Numerical,
+    Other
+  };
+
+  Exception GetExitException();
   std::string GetExitExceptionString();
+
   /**
    * Read one line of output but block for no more than timeout.
    * Returns:

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3dd2edf4ab94f5044b73b20151592c8e94a5160a
commit 3dd2edf4ab94f5044b73b20151592c8e94a5160a
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:14 2018 -0500

    cmProcess: Use explicit enum for process state
    
    Translate the values from KWSys Process.

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 904f148..1f7516c 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -154,8 +154,8 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
   this->WriteLogOutputTop(completed, total);
   std::string reason;
   bool passed = true;
-  int res =
-    started ? this->TestProcess->GetProcessStatus() : cmsysProcess_State_Error;
+  cmProcess::State res =
+    started ? this->TestProcess->GetProcessStatus() : cmProcess::State::Error;
   int retVal = this->TestProcess->GetExitValue();
   bool forceFail = false;
   bool skipped = false;
@@ -194,7 +194,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
       }
     }
   }
-  if (res == cmsysProcess_State_Exited) {
+  if (res == cmProcess::State::Exited) {
     bool success = !forceFail &&
       (retVal == 0 ||
        !this->TestProperties->RequiredRegularExpressions.empty());
@@ -215,11 +215,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
       cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Failed  " << reason);
       outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
     }
-  } else if (res == cmsysProcess_State_Expired) {
+  } else if (res == cmProcess::State::Expired) {
     cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Timeout ");
     this->TestResult.Status = cmCTestTestHandler::TIMEOUT;
     outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
-  } else if (res == cmsysProcess_State_Exception) {
+  } else if (res == cmProcess::State::Exception) {
     outputTestErrorsToConsole = this->CTest->OutputTestOutputOnTestFailure;
     cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Exception: ");
     this->TestResult.ExceptionStatus =
@@ -248,7 +248,7 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started)
     }
   } else if ("Disabled" == this->TestResult.CompletionStatus) {
     cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run (Disabled) ");
-  } else // cmsysProcess_State_Error
+  } else // cmProcess::State::Error
   {
     cmCTestLog(this->CTest, HANDLER_OUTPUT, "***Not Run ");
   }
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index a599454..fac0df9 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -156,13 +156,29 @@ int cmProcess::GetNextOutputLine(std::string& line,
   return cmsysProcess_Pipe_None;
 }
 
-// return the process status
-int cmProcess::GetProcessStatus()
+cmProcess::State cmProcess::GetProcessStatus()
 {
-  if (!this->Process) {
-    return cmsysProcess_State_Exited;
+  if (this->Process) {
+    switch (cmsysProcess_GetState(this->Process)) {
+      case cmsysProcess_State_Starting:
+        return State::Starting;
+      case cmsysProcess_State_Error:
+        return State::Error;
+      case cmsysProcess_State_Exception:
+        return State::Exception;
+      case cmsysProcess_State_Executing:
+        return State::Executing;
+      case cmsysProcess_State_Expired:
+        return State::Expired;
+      case cmsysProcess_State_Killed:
+        return State::Killed;
+      case cmsysProcess_State_Disowned:
+        return State::Disowned;
+      default: // case cmsysProcess_State_Exited:
+        break;
+    }
   }
-  return cmsysProcess_GetState(this->Process);
+  return State::Exited;
 }
 
 void cmProcess::ChangeTimeout(std::chrono::duration<double> t)
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index 32c4c74..79379aa 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -30,8 +30,19 @@ public:
   // Return true if the process starts
   bool StartProcess();
 
-  // return the process status
-  int GetProcessStatus();
+  enum class State
+  {
+    Starting,
+    Error,
+    Exception,
+    Executing,
+    Exited,
+    Expired,
+    Killed,
+    Disowned
+  };
+
+  State GetProcessStatus();
   int GetId() { return this->Id; }
   void SetId(int id) { this->Id = id; }
   int GetExitValue() { return this->ExitValue; }

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5238e6db70d275e42048479b737781fc97d82ea1
commit 5238e6db70d275e42048479b737781fc97d82ea1
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:14 2018 -0500

    cmProcess: Remove unused ReportStatus method

diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index 0db66c3..a599454 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -3,7 +3,6 @@
 #include "cmProcess.h"
 
 #include "cmProcessOutput.h"
-#include <iostream>
 
 cmProcess::cmProcess()
 {
@@ -166,64 +165,6 @@ int cmProcess::GetProcessStatus()
   return cmsysProcess_GetState(this->Process);
 }
 
-int cmProcess::ReportStatus()
-{
-  int result = 1;
-  switch (cmsysProcess_GetState(this->Process)) {
-    case cmsysProcess_State_Starting: {
-      std::cerr << "cmProcess: Never started " << this->Command
-                << " process.\n";
-    } break;
-    case cmsysProcess_State_Error: {
-      std::cerr << "cmProcess: Error executing " << this->Command
-                << " process: " << cmsysProcess_GetErrorString(this->Process)
-                << "\n";
-    } break;
-    case cmsysProcess_State_Exception: {
-      std::cerr << "cmProcess: " << this->Command
-                << " process exited with an exception: ";
-      switch (cmsysProcess_GetExitException(this->Process)) {
-        case cmsysProcess_Exception_None: {
-          std::cerr << "None";
-        } break;
-        case cmsysProcess_Exception_Fault: {
-          std::cerr << "Segmentation fault";
-        } break;
-        case cmsysProcess_Exception_Illegal: {
-          std::cerr << "Illegal instruction";
-        } break;
-        case cmsysProcess_Exception_Interrupt: {
-          std::cerr << "Interrupted by user";
-        } break;
-        case cmsysProcess_Exception_Numerical: {
-          std::cerr << "Numerical exception";
-        } break;
-        case cmsysProcess_Exception_Other: {
-          std::cerr << "Unknown";
-        } break;
-      }
-      std::cerr << "\n";
-    } break;
-    case cmsysProcess_State_Executing: {
-      std::cerr << "cmProcess: Never terminated " << this->Command
-                << " process.\n";
-    } break;
-    case cmsysProcess_State_Exited: {
-      result = cmsysProcess_GetExitValue(this->Process);
-      std::cerr << "cmProcess: " << this->Command
-                << " process exited with code " << result << "\n";
-    } break;
-    case cmsysProcess_State_Expired: {
-      std::cerr << "cmProcess: killed " << this->Command
-                << " process due to timeout.\n";
-    } break;
-    case cmsysProcess_State_Killed: {
-      std::cerr << "cmProcess: killed " << this->Command << " process.\n";
-    } break;
-  }
-  return result;
-}
-
 void cmProcess::ChangeTimeout(std::chrono::duration<double> t)
 {
   this->Timeout = t;
diff --git a/Source/CTest/cmProcess.h b/Source/CTest/cmProcess.h
index f3b0bd7..32c4c74 100644
--- a/Source/CTest/cmProcess.h
+++ b/Source/CTest/cmProcess.h
@@ -32,8 +32,6 @@ public:
 
   // return the process status
   int GetProcessStatus();
-  // Report the status of the program
-  int ReportStatus();
   int GetId() { return this->Id; }
   void SetId(int id) { this->Id = id; }
   int GetExitValue() { return this->ExitValue; }

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c13b68e61f3e89f9f52834c46a65fc7192ceb318
commit c13b68e61f3e89f9f52834c46a65fc7192ceb318
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:13 2018 -0500

    cmCTestRunTest: Modernize constructor and destructor decls

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 72a9d34..904f148 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -38,10 +38,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
   this->RunAgain = false;     // default to not having to run again
 }
 
-cmCTestRunTest::~cmCTestRunTest()
-{
-}
-
 bool cmCTestRunTest::CheckOutput()
 {
   // Read lines for up to 0.1 seconds of total time.
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 95b3e41..bde93da 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -24,8 +24,9 @@ class cmProcess;
 class cmCTestRunTest
 {
 public:
-  cmCTestRunTest(cmCTestTestHandler* handler);
-  ~cmCTestRunTest();
+  explicit cmCTestRunTest(cmCTestTestHandler* handler);
+
+  ~cmCTestRunTest() = default;
 
   void SetNumberOfRuns(int n) { this->NumberOfRunsLeft = n; }
   void SetRunUntilFailOn() { this->RunUntilFail = true; }

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4d6b09037d8c640763504ad1378d42b12ef975aa
commit 4d6b09037d8c640763504ad1378d42b12ef975aa
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:13 2018 -0500

    cmCTestRunTest: Drop unused members

diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index d5aa589..95b3e41 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -88,14 +88,6 @@ private:
   cmCTestTestHandler* TestHandler;
   cmCTest* CTest;
   cmProcess* TestProcess;
-  // If the executable to run is ctest, don't create a new process;
-  // just instantiate a new cmTest.  (Can be disabled for a single test
-  // if this option is set to false.)
-  // bool OptimizeForCTest;
-
-  bool UsePrefixCommand;
-  std::string PrefixCommand;
-
   std::string ProcessOutput;
   std::string CompressedOutput;
   double CompressionRatio;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=05da65bc22dee788576504cdd203e5fdd5f9d633
commit 05da65bc22dee788576504cdd203e5fdd5f9d633
Author:     Bryon Bean <bryon.bean at kitware.com>
AuthorDate: Mon Oct 23 08:16:45 2017 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:19:13 2018 -0500

    cmCTestMultiProcessHandler: Factor out duplicate test finish logic

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 4a980d7..453d5cb 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -195,21 +195,7 @@ bool cmCTestMultiProcessHandler::StartTestProcess(int test)
     return true;
   }
 
-  for (auto& j : this->Tests) {
-    j.second.erase(test);
-  }
-
-  this->UnlockResources(test);
-  this->Completed++;
-  this->TestFinishMap[test] = true;
-  this->TestRunningMap[test] = false;
-  this->RunningCount -= GetProcessorsUsed(test);
-  testRun->EndTest(this->Completed, this->Total, false);
-  if (!this->Properties[test]->Disabled) {
-    this->Failed->push_back(this->Properties[test]->Name);
-  }
-  delete testRun;
-
+  this->FinishTestProcess(testRun, false);
   return false;
 }
 
@@ -424,31 +410,45 @@ bool cmCTestMultiProcessHandler::CheckOutput()
     }
   }
   for (cmCTestRunTest* p : finished) {
-    this->Completed++;
-    int test = p->GetIndex();
+    this->FinishTestProcess(p, true);
+  }
+  return true;
+}
+
+void cmCTestMultiProcessHandler::FinishTestProcess(cmCTestRunTest* runner,
+                                                   bool started)
+{
+  this->Completed++;
+
+  int test = runner->GetIndex();
+  auto properties = runner->GetTestProperties();
 
-    bool testResult = p->EndTest(this->Completed, this->Total, true);
-    if (p->StartAgain()) {
+  bool testResult = runner->EndTest(this->Completed, this->Total, started);
+  if (started) {
+    if (runner->StartAgain()) {
       this->Completed--; // remove the completed test because run again
-      continue;
-    }
-    if (testResult) {
-      this->Passed->push_back(p->GetTestProperties()->Name);
-    } else {
-      this->Failed->push_back(p->GetTestProperties()->Name);
-    }
-    for (auto& t : this->Tests) {
-      t.second.erase(test);
+      return;
     }
-    this->TestFinishMap[test] = true;
-    this->TestRunningMap[test] = false;
-    this->RunningTests.erase(p);
-    this->WriteCheckpoint(test);
-    this->UnlockResources(test);
-    this->RunningCount -= GetProcessorsUsed(test);
-    delete p;
+    this->RunningTests.erase(runner);
   }
-  return true;
+
+  if (testResult) {
+    this->Passed->push_back(properties->Name);
+  } else if (!properties->Disabled) {
+    this->Failed->push_back(properties->Name);
+  }
+
+  for (auto& t : this->Tests) {
+    t.second.erase(test);
+  }
+
+  this->TestFinishMap[test] = true;
+  this->TestRunningMap[test] = false;
+  this->WriteCheckpoint(test);
+  this->UnlockResources(test);
+  this->RunningCount -= GetProcessorsUsed(test);
+
+  delete runner;
 }
 
 void cmCTestMultiProcessHandler::UpdateCostData()
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index 77a0ed9..80d6d4e 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -98,6 +98,8 @@ protected:
   // Return true if there are still tests running
   // check all running processes for output and exit case
   bool CheckOutput();
+  void FinishTestProcess(cmCTestRunTest* runner, bool started);
+
   void RemoveTest(int index);
   // Check if we need to resume an interrupted test set
   void CheckResume();

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=dd945345715b90b2a1db769865c79d86a1dfad06
commit dd945345715b90b2a1db769865c79d86a1dfad06
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Sat Dec 23 08:01:11 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Jan 10 10:18:12 2018 -0500

    cmCTestMultiProcessHandler: Add helper to make libuv use SA_RESTART
    
    Prior to 1.19, libuv does not use SA_RESTART in its signal handler.
    Add a helper to cause libuv to install its handler and then revise
    the handler's flags to add SA_RESTART.

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 6cdec8d..4a980d7 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -22,6 +22,43 @@
 #include <stdlib.h>
 #include <utility>
 
+#if defined(CMAKE_USE_SYSTEM_LIBUV) && !defined(_WIN32) &&                    \
+  UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR < 19
+#define CMAKE_UV_SIGNAL_HACK
+/*
+   libuv does not use SA_RESTART on its signal handler, but C++ streams
+   depend on it for reliable i/o operations.  This RAII helper convinces
+   libuv to install its handler, and then revises the handler to add the
+   SA_RESTART flag.  We use a distinct uv loop that never runs to avoid
+   ever really getting a callback.  libuv may fill the hack loop's signal
+   pipe and then stop writing, but that won't break any real loops.
+ */
+class cmUVSignalHackRAII
+{
+  uv_loop_t HackLoop;
+  cm::uv_signal_ptr HackSignal;
+  static void HackCB(uv_signal_t*, int) {}
+public:
+  cmUVSignalHackRAII()
+  {
+    uv_loop_init(&this->HackLoop);
+    this->HackSignal.init(this->HackLoop);
+    this->HackSignal.start(HackCB, SIGCHLD);
+    struct sigaction hack_sa;
+    sigaction(SIGCHLD, NULL, &hack_sa);
+    if (!(hack_sa.sa_flags & SA_RESTART)) {
+      hack_sa.sa_flags |= SA_RESTART;
+      sigaction(SIGCHLD, &hack_sa, NULL);
+    }
+  }
+  ~cmUVSignalHackRAII()
+  {
+    this->HackSignal.stop();
+    uv_loop_close(&this->HackLoop);
+  }
+};
+#endif
+
 class TestComparator
 {
 public:

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7e0eb77f2f0da764ba9d8a4045351bd7799e101d
commit 7e0eb77f2f0da764ba9d8a4045351bd7799e101d
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 15 15:10:43 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:01 2018 -0500

    cmCTestMultiProcessHandler: Fix StartNextTests loop on not-started test
    
    If `StartTestProcess` does not start a test, propagate this information
    back up to the `StartNextTests` loop so that it can move on to another
    candidate without allocating processors to a test that didn't run.
    Otherwise we have to wait for the next time `RunTests` loops around and
    calls `StartNextTests` again.

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index 6d71c45..6cdec8d 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -112,7 +112,7 @@ void cmCTestMultiProcessHandler::RunTests()
   this->UpdateCostData();
 }
 
-void cmCTestMultiProcessHandler::StartTestProcess(int test)
+bool cmCTestMultiProcessHandler::StartTestProcess(int test)
 {
   std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
   if (stop_time != std::chrono::system_clock::time_point() &&
@@ -121,7 +121,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test)
                                            "Stopping all tests."
                  << std::endl);
     this->StopTimePassed = true;
-    return;
+    return false;
   }
 
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
@@ -155,23 +155,25 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test)
 
   if (testRun->StartTest(this->Total)) {
     this->RunningTests.insert(testRun);
-  } else {
+    return true;
+  }
 
-    for (auto& j : this->Tests) {
-      j.second.erase(test);
-    }
+  for (auto& j : this->Tests) {
+    j.second.erase(test);
+  }
 
-    this->UnlockResources(test);
-    this->Completed++;
-    this->TestFinishMap[test] = true;
-    this->TestRunningMap[test] = false;
-    this->RunningCount -= GetProcessorsUsed(test);
-    testRun->EndTest(this->Completed, this->Total, false);
-    if (!this->Properties[test]->Disabled) {
-      this->Failed->push_back(this->Properties[test]->Name);
-    }
-    delete testRun;
+  this->UnlockResources(test);
+  this->Completed++;
+  this->TestFinishMap[test] = true;
+  this->TestRunningMap[test] = false;
+  this->RunningCount -= GetProcessorsUsed(test);
+  testRun->EndTest(this->Completed, this->Total, false);
+  if (!this->Properties[test]->Disabled) {
+    this->Failed->push_back(this->Properties[test]->Name);
   }
+  delete testRun;
+
+  return false;
 }
 
 void cmCTestMultiProcessHandler::LockResources(int index)
@@ -229,8 +231,7 @@ bool cmCTestMultiProcessHandler::StartTest(int test)
 
   // if there are no depends left then run this test
   if (this->Tests[test].empty()) {
-    this->StartTestProcess(test);
-    return true;
+    return this->StartTestProcess(test);
   }
   // This test was not able to start because it is waiting
   // on depends to run
diff --git a/Source/CTest/cmCTestMultiProcessHandler.h b/Source/CTest/cmCTestMultiProcessHandler.h
index dccc2c8..77a0ed9 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.h
+++ b/Source/CTest/cmCTestMultiProcessHandler.h
@@ -75,7 +75,7 @@ protected:
   // Start the next test or tests as many as are allowed by
   // ParallelLevel
   void StartNextTests();
-  void StartTestProcess(int test);
+  bool StartTestProcess(int test);
   bool StartTest(int test);
   // Mark the checkpoint for the given test
   void WriteCheckpoint(int index);

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=61ab5a8ef451484d3014118ed193eeba83bb22a4
commit 61ab5a8ef451484d3014118ed193eeba83bb22a4
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 15 08:36:16 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:01 2018 -0500

    cmCTestMultiProcessHandler: Check stop time more directly
    
    Avoid creating a cmCTestRunTest instance if the stop time has been
    reached.  If the stop time occurs in the small time between creating an
    instance and computing the child process timeout, we will simply compute
    a zero timeout.  This is already done for the case that we StartAgain
    after the stop time.

diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx
index ae07feb..6d71c45 100644
--- a/Source/CTest/cmCTestMultiProcessHandler.cxx
+++ b/Source/CTest/cmCTestMultiProcessHandler.cxx
@@ -13,6 +13,7 @@
 #include "cmsys/String.hxx"
 #include "cmsys/SystemInformation.hxx"
 #include <algorithm>
+#include <chrono>
 #include <iomanip>
 #include <list>
 #include <math.h>
@@ -113,6 +114,16 @@ void cmCTestMultiProcessHandler::RunTests()
 
 void cmCTestMultiProcessHandler::StartTestProcess(int test)
 {
+  std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
+  if (stop_time != std::chrono::system_clock::time_point() &&
+      stop_time <= std::chrono::system_clock::now()) {
+    cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
+                                           "Stopping all tests."
+                 << std::endl);
+    this->StopTimePassed = true;
+    return;
+  }
+
   cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT,
                      "test " << test << "\n", this->Quiet);
   this->TestRunningMap[test] = true; // mark the test as running
@@ -144,10 +155,6 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test)
 
   if (testRun->StartTest(this->Total)) {
     this->RunningTests.insert(testRun);
-  } else if (testRun->IsStopTimePassed()) {
-    this->StopTimePassed = true;
-    delete testRun;
-    return;
   } else {
 
     for (auto& j : this->Tests) {
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 6ee56ed..72a9d34 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -15,6 +15,7 @@
 #include "cmsys/RegularExpression.hxx"
 #include <chrono>
 #include <iomanip>
+#include <ratio>
 #include <sstream>
 #include <stdio.h>
 #include <utility>
@@ -32,7 +33,6 @@ cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
   this->ProcessOutput.clear();
   this->CompressedOutput.clear();
   this->CompressionRatio = 2;
-  this->StopTimePassed = false;
   this->NumberOfRunsLeft = 1; // default to 1 run of the test
   this->RunUntilFail = false; // default to run the test once
   this->RunAgain = false;     // default to not having to run again
@@ -524,15 +524,11 @@ bool cmCTestRunTest::StartTest(size_t total)
 
   std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
   if (stop_time != std::chrono::system_clock::time_point()) {
-    auto stop_timeout =
+    std::chrono::duration<double> stop_timeout =
       (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
 
     if (stop_timeout <= std::chrono::duration<double>::zero()) {
-      cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
-                                             "Stopping all tests."
-                   << std::endl);
-      this->StopTimePassed = true;
-      return false;
+      stop_timeout = std::chrono::duration<double>::zero();
     }
     if (timeout == std::chrono::duration<double>::zero() ||
         stop_timeout < timeout) {
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index 136b9ef..d5aa589 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -50,8 +50,6 @@ public:
 
   std::string GetProcessOutput() { return this->ProcessOutput; }
 
-  bool IsStopTimePassed() { return this->StopTimePassed; }
-
   cmCTestTestHandler::cmCTestTestResult GetTestResults()
   {
     return this->TestResult;
@@ -108,7 +106,6 @@ private:
   std::string StartTime;
   std::string ActualCommand;
   std::vector<std::string> Arguments;
-  bool StopTimePassed;
   bool RunUntilFail;
   int NumberOfRunsLeft;
   bool RunAgain;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4c199a4c28a0647c0277c7009b5f6e81b26333bb
commit 4c199a4c28a0647c0277c7009b5f6e81b26333bb
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 15 08:24:24 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:01 2018 -0500

    cmCTestRunTest: Subsume ResolveTimeout into only call site

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 8050b9a..6ee56ed 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -520,11 +520,26 @@ bool cmCTestRunTest::StartTest(size_t total)
   }
   this->StartTime = this->CTest->CurrentTime();
 
-  auto timeout = this->ResolveTimeout();
+  auto timeout = this->TestProperties->Timeout;
 
-  if (this->StopTimePassed) {
-    return false;
+  std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
+  if (stop_time != std::chrono::system_clock::time_point()) {
+    auto stop_timeout =
+      (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
+
+    if (stop_timeout <= std::chrono::duration<double>::zero()) {
+      cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
+                                             "Stopping all tests."
+                   << std::endl);
+      this->StopTimePassed = true;
+      return false;
+    }
+    if (timeout == std::chrono::duration<double>::zero() ||
+        stop_timeout < timeout) {
+      timeout = stop_timeout;
+    }
   }
+
   return this->ForkProcess(timeout, this->TestProperties->ExplicitTimeout,
                            &this->TestProperties->Environment);
 }
@@ -601,30 +616,6 @@ void cmCTestRunTest::DartProcessing()
   }
 }
 
-std::chrono::duration<double> cmCTestRunTest::ResolveTimeout()
-{
-  auto timeout = this->TestProperties->Timeout;
-
-  std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
-  if (stop_time == std::chrono::system_clock::time_point()) {
-    return timeout;
-  }
-
-  auto stop_timeout =
-    (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
-
-  if (stop_timeout <= std::chrono::duration<double>::zero()) {
-    cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
-                                           "Stopping all tests."
-                 << std::endl);
-    this->StopTimePassed = true;
-    return std::chrono::duration<double>::zero();
-  }
-  return timeout == std::chrono::duration<double>::zero()
-    ? stop_timeout
-    : (timeout < stop_timeout ? timeout : stop_timeout);
-}
-
 bool cmCTestRunTest::ForkProcess(std::chrono::duration<double> testTimeOut,
                                  bool explicitTimeout,
                                  std::vector<std::string>* environment)
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index cd380ca..136b9ef 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -78,8 +78,6 @@ private:
   bool NeedsToRerun();
   void DartProcessing();
   void ExeNotFound(std::string exe);
-  // Figures out a final timeout which is min(STOP_TIME, NOW+TIMEOUT)
-  std::chrono::duration<double> ResolveTimeout();
   bool ForkProcess(std::chrono::duration<double> testTimeOut,
                    bool explicitTimeout,
                    std::vector<std::string>* environment);

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2567e5df69c1a4276c5e51dfa6c49482b24b1545
commit 2567e5df69c1a4276c5e51dfa6c49482b24b1545
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 15 07:49:26 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:00 2018 -0500

    cmCTest: Refactor stop time calculations
    
    Calculate the stop time up front instead of re-parsing its string for
    every test.

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 0a27138..8050b9a 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -9,7 +9,6 @@
 #include "cmSystemTools.h"
 #include "cmWorkingDirectory.h"
 
-#include "cm_curl.h"
 #include "cm_zlib.h"
 #include "cmsys/Base64.h"
 #include "cmsys/Process.h"
@@ -18,7 +17,6 @@
 #include <iomanip>
 #include <sstream>
 #include <stdio.h>
-#include <time.h>
 #include <utility>
 
 cmCTestRunTest::cmCTestRunTest(cmCTestTestHandler* handler)
@@ -607,48 +605,13 @@ std::chrono::duration<double> cmCTestRunTest::ResolveTimeout()
 {
   auto timeout = this->TestProperties->Timeout;
 
-  if (this->CTest->GetStopTime().empty()) {
+  std::chrono::system_clock::time_point stop_time = this->CTest->GetStopTime();
+  if (stop_time == std::chrono::system_clock::time_point()) {
     return timeout;
   }
-  struct tm* lctime;
-  time_t current_time = time(nullptr);
-  lctime = gmtime(&current_time);
-  int gm_hour = lctime->tm_hour;
-  time_t gm_time = mktime(lctime);
-  lctime = localtime(&current_time);
-  int local_hour = lctime->tm_hour;
 
-  int tzone_offset = local_hour - gm_hour;
-  if (gm_time > current_time && gm_hour < local_hour) {
-    // this means gm_time is on the next day
-    tzone_offset -= 24;
-  } else if (gm_time < current_time && gm_hour > local_hour) {
-    // this means gm_time is on the previous day
-    tzone_offset += 24;
-  }
-
-  tzone_offset *= 100;
-  char buf[1024];
-  // add todays year day and month to the time in str because
-  // curl_getdate no longer assumes the day is today
-  sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
-          lctime->tm_mon + 1, lctime->tm_mday,
-          this->CTest->GetStopTime().c_str(), tzone_offset);
-
-  time_t stop_time_t = curl_getdate(buf, &current_time);
-  if (stop_time_t == -1) {
-    return timeout;
-  }
-
-  auto stop_time = std::chrono::system_clock::from_time_t(stop_time_t);
-
-  // the stop time refers to the next day
-  if (this->CTest->NextDayStopTime) {
-    stop_time += std::chrono::hours(24);
-  }
   auto stop_timeout =
-    (stop_time - std::chrono::system_clock::from_time_t(current_time)) %
-    std::chrono::hours(24);
+    (stop_time - std::chrono::system_clock::now()) % std::chrono::hours(24);
 
   if (stop_timeout <= std::chrono::duration<double>::zero()) {
     cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 339bf5a..fd7c5e8 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -281,8 +281,6 @@ cmCTest::cmCTest()
   this->GlobalTimeout = std::chrono::duration<double>::zero();
   this->CompressXMLFiles = false;
   this->ScheduleType.clear();
-  this->StopTime.clear();
-  this->NextDayStopTime = false;
   this->OutputLogFile = nullptr;
   this->OutputLogFileLastTag = -1;
   this->SuppressUpdatingCTestConfiguration = false;
@@ -2268,10 +2266,41 @@ void cmCTest::SetNotesFiles(const char* notes)
   this->NotesFiles = notes;
 }
 
-void cmCTest::SetStopTime(std::string const& time)
+void cmCTest::SetStopTime(std::string const& time_str)
 {
-  this->StopTime = time;
-  this->DetermineNextDayStop();
+
+  struct tm* lctime;
+  time_t current_time = time(nullptr);
+  lctime = gmtime(&current_time);
+  int gm_hour = lctime->tm_hour;
+  time_t gm_time = mktime(lctime);
+  lctime = localtime(&current_time);
+  int local_hour = lctime->tm_hour;
+
+  int tzone_offset = local_hour - gm_hour;
+  if (gm_time > current_time && gm_hour < local_hour) {
+    // this means gm_time is on the next day
+    tzone_offset -= 24;
+  } else if (gm_time < current_time && gm_hour > local_hour) {
+    // this means gm_time is on the previous day
+    tzone_offset += 24;
+  }
+
+  tzone_offset *= 100;
+  char buf[1024];
+  sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
+          lctime->tm_mon + 1, lctime->tm_mday, time_str.c_str(), tzone_offset);
+
+  time_t stop_time = curl_getdate(buf, &current_time);
+  if (stop_time == -1) {
+    this->StopTime = std::chrono::system_clock::time_point();
+    return;
+  }
+  this->StopTime = std::chrono::system_clock::from_time_t(stop_time);
+
+  if (stop_time < current_time) {
+    this->StopTime += std::chrono::hours(24);
+  }
 }
 
 int cmCTest::ReadCustomConfigurationFileTree(const char* dir, cmMakefile* mf)
@@ -2429,38 +2458,6 @@ void cmCTest::EmptyCTestConfiguration()
   this->CTestConfiguration.clear();
 }
 
-void cmCTest::DetermineNextDayStop()
-{
-  struct tm* lctime;
-  time_t current_time = time(nullptr);
-  lctime = gmtime(&current_time);
-  int gm_hour = lctime->tm_hour;
-  time_t gm_time = mktime(lctime);
-  lctime = localtime(&current_time);
-  int local_hour = lctime->tm_hour;
-
-  int tzone_offset = local_hour - gm_hour;
-  if (gm_time > current_time && gm_hour < local_hour) {
-    // this means gm_time is on the next day
-    tzone_offset -= 24;
-  } else if (gm_time < current_time && gm_hour > local_hour) {
-    // this means gm_time is on the previous day
-    tzone_offset += 24;
-  }
-
-  tzone_offset *= 100;
-  char buf[1024];
-  sprintf(buf, "%d%02d%02d %s %+05i", lctime->tm_year + 1900,
-          lctime->tm_mon + 1, lctime->tm_mday, this->StopTime.c_str(),
-          tzone_offset);
-
-  time_t stop_time = curl_getdate(buf, &current_time);
-
-  if (stop_time < current_time) {
-    this->NextDayStopTime = true;
-  }
-}
-
 void cmCTest::SetCTestConfiguration(const char* name, const char* value,
                                     bool suppress)
 {
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index e1cf25e..61487f1 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -226,7 +226,10 @@ public:
   bool ShouldCompressTestOutput();
   bool CompressString(std::string& str);
 
-  std::string GetStopTime() { return this->StopTime; }
+  std::chrono::system_clock::time_point GetStopTime()
+  {
+    return this->StopTime;
+  }
   void SetStopTime(std::string const& time);
 
   /** Used for parallel ctest job scheduling */
@@ -464,8 +467,7 @@ private:
   bool RepeatUntilFail;
   std::string ConfigType;
   std::string ScheduleType;
-  std::string StopTime;
-  bool NextDayStopTime;
+  std::chrono::system_clock::time_point StopTime;
   bool Verbose;
   bool ExtraVerbose;
   bool ProduceXML;
@@ -481,8 +483,6 @@ private:
 
   int GenerateNotesFile(const char* files);
 
-  void DetermineNextDayStop();
-
   // these are helper classes
   typedef std::map<std::string, cmCTestGenericHandler*> t_TestingHandlers;
   t_TestingHandlers TestingHandlers;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=1138feb38f4e6d259ded23312b7f0f2184ac816a
commit 1138feb38f4e6d259ded23312b7f0f2184ac816a
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 15 07:20:54 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:00 2018 -0500

    cmCTest: Remove unused member LastStopTimeout
    
    This member was added by commit v2.8.2~285 (Better detection of
    stop_time being passed, 2010-03-19), but its logic has no effect.
    The member is only used for comparison against a value to which
    it was just assigned.

diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index dbdefae..0a27138 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -649,10 +649,8 @@ std::chrono::duration<double> cmCTestRunTest::ResolveTimeout()
   auto stop_timeout =
     (stop_time - std::chrono::system_clock::from_time_t(current_time)) %
     std::chrono::hours(24);
-  this->CTest->LastStopTimeout = stop_timeout;
 
-  if (stop_timeout <= std::chrono::duration<double>::zero() ||
-      stop_timeout > this->CTest->LastStopTimeout) {
+  if (stop_timeout <= std::chrono::duration<double>::zero()) {
     cmCTestLog(this->CTest, ERROR_MESSAGE, "The stop time has been passed. "
                                            "Stopping all tests."
                  << std::endl);
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 26e1dcb..339bf5a 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -279,7 +279,6 @@ cmCTest::cmCTest()
   this->InteractiveDebugMode = true;
   this->TimeOut = std::chrono::duration<double>::zero();
   this->GlobalTimeout = std::chrono::duration<double>::zero();
-  this->LastStopTimeout = std::chrono::hours(24);
   this->CompressXMLFiles = false;
   this->ScheduleType.clear();
   this->StopTime.clear();
diff --git a/Source/cmCTest.h b/Source/cmCTest.h
index 23d71cb..e1cf25e 100644
--- a/Source/cmCTest.h
+++ b/Source/cmCTest.h
@@ -512,8 +512,6 @@ private:
 
   std::chrono::duration<double> GlobalTimeout;
 
-  std::chrono::duration<double> LastStopTimeout;
-
   int MaxTestNameWidth;
 
   int ParallelLevel;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4ffb0f8b45a5abd51a04a399461c9096019a87f8
commit 4ffb0f8b45a5abd51a04a399461c9096019a87f8
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Fri Dec 22 20:24:33 2017 -0500
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Mon Jan 8 12:55:00 2018 -0500

    libuv: unix: restart syscalls interrupted by our signal handler
    
    BSD `signal(2)` semantics make some system calls (e.g. for `write`)
    restartable when interrupted by a signal handler.  Use `SA_RESTART` to
    enable these semantics everywhere that supports them.
    
    This is required by C++ stream libraries that interpret `EINTR` as any
    other error, set `badbit`, and stop writing.  I've observed this with
    `libstdc++` during a `std::cout.flush()` call interrupted by `SIGCHLD`.

diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c
index cb09ead..3759778 100644
--- a/Utilities/cmlibuv/src/unix/signal.c
+++ b/Utilities/cmlibuv/src/unix/signal.c
@@ -28,6 +28,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#ifndef SA_RESTART
+# define SA_RESTART 0
+#endif
 
 typedef struct {
   uv_signal_t* handle;
@@ -216,7 +219,9 @@ static int uv__signal_register_handler(int signum, int oneshot) {
   if (sigfillset(&sa.sa_mask))
     abort();
   sa.sa_handler = uv__signal_handler;
-  sa.sa_flags = oneshot ? SA_RESETHAND : 0;
+  sa.sa_flags = SA_RESTART;
+  if (oneshot)
+    sa.sa_flags |= SA_RESETHAND;
 
   /* XXX save old action so we can restore it later on? */
   if (sigaction(signum, &sa, NULL))

-----------------------------------------------------------------------

Summary of changes:
 Source/CTest/cmCTestMultiProcessHandler.cxx |  173 ++++---
 Source/CTest/cmCTestMultiProcessHandler.h   |   12 +-
 Source/CTest/cmCTestRunTest.cxx             |  201 +++-----
 Source/CTest/cmCTestRunTest.h               |   30 +-
 Source/CTest/cmProcess.cxx                  |  708 ++++++++++++++++++++++-----
 Source/CTest/cmProcess.h                    |   79 ++-
 Source/cmCTest.cxx                          |   72 ++-
 Source/cmCTest.h                            |   12 +-
 Utilities/cmlibuv/src/unix/signal.c         |    7 +-
 9 files changed, 882 insertions(+), 412 deletions(-)


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list