From c76c9b57ed93f841daa437a04c0c8aeaab000216 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 22 Aug 2025 22:28:55 -0500 Subject: [PATCH] Wait for an initial offset prior to proceeding with initialization --- .../source/scwx/qt/manager/task_manager.cpp | 1 + wxdata/include/scwx/network/ntp_client.hpp | 2 + wxdata/source/scwx/network/ntp_client.cpp | 49 +++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/manager/task_manager.cpp b/scwx-qt/source/scwx/qt/manager/task_manager.cpp index 130318f5..66b7285a 100644 --- a/scwx-qt/source/scwx/qt/manager/task_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/task_manager.cpp @@ -17,6 +17,7 @@ void Initialize() ntpClient_ = network::NtpClient::Instance(); ntpClient_->Start(); + ntpClient_->WaitForInitialOffset(); } void Shutdown() diff --git a/wxdata/include/scwx/network/ntp_client.hpp b/wxdata/include/scwx/network/ntp_client.hpp index 6462a6e9..beb4be21 100644 --- a/wxdata/include/scwx/network/ntp_client.hpp +++ b/wxdata/include/scwx/network/ntp_client.hpp @@ -35,6 +35,8 @@ public: std::string RotateServer(); void RunOnce(); + void WaitForInitialOffset(); + static std::shared_ptr Instance(); private: diff --git a/wxdata/source/scwx/network/ntp_client.cpp b/wxdata/source/scwx/network/ntp_client.cpp index 45c0ad74..0a340f87 100644 --- a/wxdata/source/scwx/network/ntp_client.cpp +++ b/wxdata/source/scwx/network/ntp_client.cpp @@ -3,6 +3,9 @@ #include #include +#include +#include + #include #include #include @@ -112,6 +115,8 @@ public: void Run(); void RunOnce(); + void FinishInitialization(); + boost::asio::thread_pool threadPool_ {2u}; boost::asio::steady_timer pollTimer_ {threadPool_}; @@ -122,6 +127,10 @@ public: bool disableServer_ {false}; bool rotateServer_ {false}; + std::mutex initializationMutex_ {}; + std::condition_variable initializationCondition_ {}; + std::atomic initialized_ {false}; + types::ntp::NtpPacket transmitPacket_ {}; boost::asio::ip::udp::socket socket_ {threadPool_}; @@ -164,6 +173,14 @@ NtpClient::Impl::Impl() transmitPacket_.fields.vn = 3; // Version transmitPacket_.fields.mode = 3; // Client (3) + + // If the NTP client is enabled, wait until the first refresh to consider + // "initialized". Otherwise, mark as initialized immediately to prevent a + // deadlock. + if (!enabled_) + { + initialized_ = true; + } } NtpClient::Impl::~Impl() @@ -253,7 +270,7 @@ void NtpClient::Impl::Poll() { using namespace std::chrono_literals; - static constexpr auto kTimeout_ = 15s; + static constexpr auto kTimeout_ = 5s; try { @@ -359,8 +376,6 @@ void NtpClient::Impl::ReceivePacket(std::size_t length) timeOffset_ = ((t1 - t0) + (t2 - t3)) / 2; logger_->debug("Time offset updated: {:%jd %T}", timeOffset_); - - // TODO: Signal } } else @@ -496,6 +511,34 @@ void NtpClient::Impl::RunOnce() // Did not poll this frame error_ = true; } + + FinishInitialization(); +} + +void NtpClient::Impl::FinishInitialization() +{ + if (!initialized_) + { + // Set initialized to true + std::unique_lock lock(initializationMutex_); + initialized_ = true; + lock.unlock(); + + // Notify any threads waiting for initialization + initializationCondition_.notify_all(); + } +} + +void NtpClient::WaitForInitialOffset() +{ + std::unique_lock lock(p->initializationMutex_); + + // While not yet initialized + while (!p->initialized_) + { + // Wait for initialization + p->initializationCondition_.wait(lock); + } } std::shared_ptr NtpClient::Instance()