diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index da63da1d4a..2ff4d14fa5 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -869,7 +869,7 @@ bool cmCTestBuildHandler::RunMakeCommand(std::string const& command, auto* timedOutPtr = static_cast(t->data); *timedOutPtr = true; }, - timeout * 1000, 0); + timeout * 1000, 0, cm::uv_update_time::yes); } // For every chunk of data diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index d5a84e5a07..1c4f2a5872 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -773,7 +773,7 @@ void cmCTestMultiProcessHandler::StartNextTestsOnTimer() auto* self = static_cast(timer->data); self->StartNextTests(); }, - milliseconds, 0); + milliseconds, 0, cm::uv_update_time::no); } void cmCTestMultiProcessHandler::FinishTestProcess( diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx index 70a1ebde63..9002d2e1b6 100644 --- a/Source/CTest/cmProcess.cxx +++ b/Source/CTest/cmProcess.cxx @@ -162,7 +162,8 @@ void cmProcess::StartTimer() auto msec = std::chrono::duration_cast(*this->Timeout); this->Timer.start(&cmProcess::OnTimeoutCB, - static_cast(msec.count()), 0); + static_cast(msec.count()), 0, + cm::uv_update_time::no); } } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 8da4cfcbfb..f8a1a15b01 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -3285,7 +3285,8 @@ bool cmCTest::RunCommand(std::vector const& args, auto* timedOutPtr = static_cast(t->data); *timedOutPtr = true; }, - static_cast(timeout.count() * 1000.0), 0); + static_cast(timeout.count() * 1000.0), 0, + cm::uv_update_time::yes); } std::vector tempOutput; diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 4a4af166d1..698a7fcce5 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -320,7 +320,7 @@ bool cmExecuteProcessCommand(std::vector const& args, auto* timeoutPtr = static_cast(handle->data); *timeoutPtr = true; }, - timeoutMillis, 0); + timeoutMillis, 0, cm::uv_update_time::yes); } // Read the process output. diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 45c3fd58ac..0d0102ede8 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -890,7 +890,8 @@ bool cmSystemTools::RunSingleCommand(std::vector const& command, auto* timedOutPtr = static_cast(t->data); *timedOutPtr = true; }, - static_cast(timeout.count() * 1000.0), 0); + static_cast(timeout.count() * 1000.0), 0, + cm::uv_update_time::yes); } std::vector tempStdOut; @@ -2862,7 +2863,8 @@ cmSystemTools::WaitForLineResult cmSystemTools::WaitForLine( auto* timedOutPtr = static_cast(handle->data); *timedOutPtr = true; }, - static_cast(timeout.count() * 1000.0), 0); + static_cast(timeout.count() * 1000.0), 0, + cm::uv_update_time::no); uv_run(loop, UV_RUN_ONCE); if (timedOut) { diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx index 201e804e2b..ff42b58ce2 100644 --- a/Source/cmUVHandlePtr.cxx +++ b/Source/cmUVHandlePtr.cxx @@ -243,9 +243,13 @@ int uv_timer_ptr::init(uv_loop_t& loop, void* data) return uv_timer_init(&loop, *this); } -int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) +int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat, + uv_update_time update_time) { assert(this->handle); + if (update_time == uv_update_time::yes) { + ::uv_update_time(this->handle->loop); + } return uv_timer_start(*this, cb, timeout, repeat); } diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h index 6c2260ec1b..d1dbb97545 100644 --- a/Source/cmUVHandlePtr.h +++ b/Source/cmUVHandlePtr.h @@ -30,6 +30,20 @@ namespace cm { +/** Whether to call uv_update_time before starting a timer. + * + * uv_loop_t caches a "now" time that uv_loop_init initializes and + * uv_run updates on each event loop iteration. uv_timer_start + * computes timer expiry relative to the loop's cached "now" time. + * For short timeouts started before the event loop, we may need to + * update the "now" time when starting the timer. + */ +enum class uv_update_time +{ + no, + yes, +}; + /*** * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes * making sure resources are properly freed. @@ -251,7 +265,8 @@ struct uv_timer_ptr : public uv_handle_ptr_ int init(uv_loop_t& loop, void* data = nullptr); - int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat); + int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat, + uv_update_time update_time); void stop(); }; diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index e551083439..6b491aaf1f 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -454,7 +454,7 @@ bool cmUVProcessChain::Wait(uint64_t milliseconds) auto* timeoutPtr = static_cast(handle->data); *timeoutPtr = true; }, - milliseconds, 0); + milliseconds, 0, cm::uv_update_time::yes); } while (!timeout && diff --git a/Tests/CMakeLib/testUVHandlePtr.cxx b/Tests/CMakeLib/testUVHandlePtr.cxx index 17f672d072..579e52dc1e 100644 --- a/Tests/CMakeLib/testUVHandlePtr.cxx +++ b/Tests/CMakeLib/testUVHandlePtr.cxx @@ -74,7 +74,7 @@ static bool testTimer() cm::uv_timer_ptr timer; timer.init(*loop, &timed); - timer.start(cb, 10, 0); + timer.start(cb, 10, 0, cm::uv_update_time::no); uv_run(loop, UV_RUN_DEFAULT); if (!timed) { @@ -83,7 +83,7 @@ static bool testTimer() } timed = false; - timer.start(cb, 10, 0); + timer.start(cb, 10, 0, cm::uv_update_time::no); timer.stop(); uv_run(loop, UV_RUN_DEFAULT);