From 9380c3975cbc17b0c828c2d9f1586c6b6c89c66c Mon Sep 17 00:00:00 2001 From: Johannes Schmidt Date: Thu, 25 Jun 2026 10:35:42 +0200 Subject: [PATCH] Replace `deadline_timer` with `steady_timer` everwhere --- lib/base/io-engine.cpp | 10 +++--- lib/base/io-engine.hpp | 9 +++--- lib/base/tlsstream.cpp | 2 +- lib/icingadb/redisconnection.cpp | 8 ++--- lib/icingadb/redisconnection.hpp | 7 +++-- lib/methods/ifwapichecktask.cpp | 6 ++-- lib/otel/otel.cpp | 4 +-- lib/remote/apilistener.cpp | 9 ++++-- lib/remote/eventqueue.cpp | 8 ++--- lib/remote/eventqueue.hpp | 6 ++-- lib/remote/httpserverconnection.cpp | 2 +- lib/remote/httpserverconnection.hpp | 4 +-- lib/remote/jsonrpcconnection-heartbeat.cpp | 2 +- lib/remote/jsonrpcconnection.cpp | 6 ++-- lib/remote/jsonrpcconnection.hpp | 2 +- test/base-io-engine.cpp | 36 +++++++++++----------- test/remote-httpserverconnection.cpp | 4 +-- 17 files changed, 64 insertions(+), 61 deletions(-) diff --git a/lib/base/io-engine.cpp b/lib/base/io-engine.cpp index 9da8d1f549e..bb9f3014427 100644 --- a/lib/base/io-engine.cpp +++ b/lib/base/io-engine.cpp @@ -181,17 +181,18 @@ void IoEngine::RunEventLoop() AsioEvent::AsioEvent(boost::asio::io_context& io, bool init) : m_Timer(io) { - m_Timer.expires_at(init ? boost::posix_time::neg_infin : boost::posix_time::pos_infin); + using boost::asio::steady_timer; + m_Timer.expires_at(init ? steady_timer::time_point::min() : steady_timer::time_point::max()); } void AsioEvent::Set() { - m_Timer.expires_at(boost::posix_time::neg_infin); + m_Timer.expires_at(boost::asio::steady_timer::time_point::min()); } void AsioEvent::Clear() { - m_Timer.expires_at(boost::posix_time::pos_infin); + m_Timer.expires_at(boost::asio::steady_timer::time_point::max()); } void AsioEvent::Wait(boost::asio::yield_context yc) @@ -258,6 +259,5 @@ void Timeout::Cancel() { m_Cancelled->store(true); - boost::system::error_code ec; - m_Timer.cancel(ec); + m_Timer.cancel(); } diff --git a/lib/base/io-engine.hpp b/lib/base/io-engine.hpp index cc2eb72de04..4aafd674854 100644 --- a/lib/base/io-engine.hpp +++ b/lib/base/io-engine.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -197,7 +196,7 @@ class AsioEvent void Wait(boost::asio::yield_context yc); private: - boost::asio::deadline_timer m_Timer; + boost::asio::steady_timer m_Timer; }; /** @@ -225,7 +224,7 @@ class AsioDualEvent * * This class provides a workaround for Boost.ASIO's lack of built-in timeout support. * While Boost.ASIO handles asynchronous operations, it does not natively support timeouts for these operations. - * This class uses a boost::asio::deadline_timer to emulate a timeout by scheduling a callback to be triggered + * This class uses a boost::asio::steady_timer to emulate a timeout by scheduling a callback to be triggered * after a specified duration, effectively adding timeout behavior where none exists. * The callback is executed within the provided strand, ensuring thread-safety. * @@ -244,7 +243,7 @@ class AsioDualEvent class Timeout { public: - using Timer = boost::asio::deadline_timer; + using Timer = boost::asio::steady_timer; /** * Schedules onTimeout to be triggered after timeoutFromNow on strand. @@ -255,7 +254,7 @@ class Timeout * @param onTimeout The callback to invoke when the timeout occurs. */ template - Timeout(boost::asio::io_context::strand& strand, const Timer::duration_type& timeoutFromNow, OnTimeout onTimeout) + Timeout(boost::asio::io_context::strand& strand, const Timer::duration& timeoutFromNow, OnTimeout onTimeout) : m_Timer(strand.context(), timeoutFromNow), m_Cancelled(Shared>::Make(false)) { ASSERT(IoEngine::IsStrandRunningOnThisThread(strand)); diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp index c17d7131b4e..c10caee0676 100644 --- a/lib/base/tlsstream.cpp +++ b/lib/base/tlsstream.cpp @@ -141,7 +141,7 @@ void AsioTlsStream::GracefulDisconnect(boost::asio::io_context::strand& strand, } { - Timeout shutdownTimeout (strand, boost::posix_time::seconds(10), + Timeout shutdownTimeout (strand, 10s, [this] { // Forcefully terminate the connection if async_shutdown() blocked more than 10 seconds. ForceDisconnect(); diff --git a/lib/icingadb/redisconnection.cpp b/lib/icingadb/redisconnection.cpp index bd279db2ad7..8116a97d40a 100644 --- a/lib/icingadb/redisconnection.cpp +++ b/lib/icingadb/redisconnection.cpp @@ -285,7 +285,7 @@ void RedisConnection::Connect(asio::yield_context& yc) { Defer notConnecting ([this]() { m_Connecting.store(m_Connected.load()); }); - boost::asio::deadline_timer timer (m_Strand.context()); + boost::asio::steady_timer timer (m_Strand.context()); for (;;) { try { @@ -363,7 +363,7 @@ void RedisConnection::Connect(asio::yield_context& yc) << "'): " << ex.what(); } - timer.expires_from_now(boost::posix_time::seconds(5)); + timer.expires_after(5s); timer.async_wait(yc); } @@ -476,11 +476,11 @@ void RedisConnection::LogStats(asio::yield_context& yc) { double lastMessage = 0; - m_LogStatsTimer.expires_from_now(boost::posix_time::seconds(10)); + m_LogStatsTimer.expires_after(10s); for (;;) { m_LogStatsTimer.async_wait(yc); - m_LogStatsTimer.expires_from_now(boost::posix_time::seconds(10)); + m_LogStatsTimer.expires_after(10s); if (!IsConnected()) continue; diff --git a/lib/icingadb/redisconnection.hpp b/lib/icingadb/redisconnection.hpp index 7a83f0c040c..d5fbbe066ab 100644 --- a/lib/icingadb/redisconnection.hpp +++ b/lib/icingadb/redisconnection.hpp @@ -17,7 +17,7 @@ #include "base/value.hpp" #include #include -#include +#include #include #include #include @@ -347,7 +347,7 @@ struct RedisConnInfo final : SharedObject // Number of pending Redis queries, always 0 if m_Parent is set unless m_TrackOwnPendingQueries is true. std::atomic_size_t m_PendingQueries{0}; bool m_TrackOwnPendingQueries; // Whether to track pending queries even if m_Parent is set. - boost::asio::deadline_timer m_LogStatsTimer; + boost::asio::steady_timer m_LogStatsTimer; Ptr m_Parent; }; @@ -568,9 +568,10 @@ void RedisConnection::Handshake(StreamPtr& strm, boost::asio::yield_context& yc) template Timeout RedisConnection::MakeTimeout(StreamPtr& stream) { + std::chrono::duration connectTimeout{m_ConnInfo->ConnectTimeout}; return Timeout( m_Strand, - boost::posix_time::microseconds(intmax_t(m_ConnInfo->ConnectTimeout * 1000000)), + std::chrono::duration_cast(connectTimeout), [stream] { boost::system::error_code ec; stream->lowest_layer().cancel(ec); diff --git a/lib/methods/ifwapichecktask.cpp b/lib/methods/ifwapichecktask.cpp index 10fb3e67a4f..f3aa6ee6279 100644 --- a/lib/methods/ifwapichecktask.cpp +++ b/lib/methods/ifwapichecktask.cpp @@ -357,11 +357,11 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes } } - auto checkTimeout (command->GetTimeout()); + std::chrono::duration checkTimeout{command->GetTimeout()}; auto checkableTimeout (checkable->GetCheckTimeout()); if (!checkableTimeout.IsEmpty()) - checkTimeout = checkableTimeout; + checkTimeout = std::chrono::duration{checkableTimeout.Get()}; if (resolvedMacros && !useResolvedMacros) return; @@ -457,7 +457,7 @@ void IfwApiCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckRes IoEngine::SpawnCoroutine( *strand, [strand, checkable, cr, psCommand, psHost, expectedSan, psPort, conn, req, checkTimeout, reportResult = std::move(reportResult)](asio::yield_context yc) { - Timeout timeout (*strand, boost::posix_time::microseconds(int64_t(checkTimeout * 1e6)), + Timeout timeout (*strand, std::chrono::duration_cast(checkTimeout), [&conn, &checkable] { Log(LogNotice, "IfwApiCheckTask") << "Timeout while checking " << checkable->GetReflectionType()->GetName() diff --git a/lib/otel/otel.cpp b/lib/otel/otel.cpp index 42be64f3ae5..4bfca53bbbc 100644 --- a/lib/otel/otel.cpp +++ b/lib/otel/otel.cpp @@ -112,7 +112,7 @@ void OTel::Stop() // below, and we would end up blocking indefinitely, so we have to check the exporting // state here first. if (Exporting()) { - Timeout writerTimeout(m_Strand, boost::posix_time::seconds(5), [this] { + Timeout writerTimeout(m_Strand, 5s, [this] { boost::system::error_code ec; std::visit([&ec](auto& stream) { stream->lowest_layer().cancel(ec); }, *m_Stream); }); @@ -246,7 +246,7 @@ void OTel::Connect(boost::asio::yield_context& yc) stream = Shared::Make(m_Strand.context()); } - Timeout timeout{m_Strand, boost::posix_time::seconds(10), [this, stream] { + Timeout timeout{m_Strand, 10s, [this, stream] { Log(LogCritical, "OTelExporter") << "Timeout while connecting to OpenTelemetry backend '" << m_ConnInfo.Host << ":" << m_ConnInfo.Port << "', cancelling attempt."; diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index aa13eaf5646..ad0276d1011 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -572,7 +572,8 @@ void ApiListener::ListenerCoroutineProc(boost::asio::yield_context yc, const Sha auto strand (Shared::Make(io)); IoEngine::SpawnCoroutine(*strand, [this, strand, sslConn, remoteEndpoint](asio::yield_context yc) { - Timeout timeout (*strand, boost::posix_time::microseconds(int64_t(GetConnectTimeout() * 1e6)), + std::chrono::duration connectTo{GetConnectTimeout()}; + Timeout timeout (*strand, std::chrono::duration_cast(connectTo), [sslConn, remoteEndpoint] { Log(LogWarning, "ApiListener") << "Timeout while processing incoming connection from " << remoteEndpoint; @@ -628,7 +629,8 @@ void ApiListener::AddConnection(const Endpoint::Ptr& endpoint) lock.unlock(); - Timeout timeout (*strand, boost::posix_time::microseconds(int64_t(GetConnectTimeout() * 1e6)), + std::chrono::duration connectTimeout{GetConnectTimeout()}; + Timeout timeout (*strand, std::chrono::duration_cast(connectTimeout), [sslConn, endpoint, host, port] { Log(LogCritical, "ApiListener") << "Timeout while reconnecting to endpoint '" << endpoint->GetName() << "' via host '" << host @@ -721,9 +723,10 @@ void ApiListener::NewClientHandlerInternal( boost::system::error_code ec; { + std::chrono::duration tlsHandShakeTimeout{Configuration::TlsHandshakeTimeout}; Timeout handshakeTimeout ( *strand, - boost::posix_time::microseconds(intmax_t(Configuration::TlsHandshakeTimeout * 1000000)), + std::chrono::duration_cast(tlsHandShakeTimeout), [client] { boost::system::error_code ec; client->lowest_layer().cancel(ec); diff --git a/lib/remote/eventqueue.cpp b/lib/remote/eventqueue.cpp index 49464a0e18e..7e50fe49da3 100644 --- a/lib/remote/eventqueue.cpp +++ b/lib/remote/eventqueue.cpp @@ -174,14 +174,14 @@ void EventsInbox::Push(Dictionary::Ptr event) std::unique_lock lock (m_Mutex); m_Queue.emplace(std::move(event)); - m_Timer.expires_at(boost::posix_time::neg_infin); + m_Timer.expires_at(boost::asio::steady_timer::time_point::min()); } -Dictionary::Ptr EventsInbox::Shift(boost::asio::yield_context yc, double timeout) +Dictionary::Ptr EventsInbox::Shift(boost::asio::yield_context yc, std::chrono::milliseconds timeout) { std::unique_lock lock (m_Mutex, std::defer_lock); - m_Timer.expires_at(boost::posix_time::neg_infin); + m_Timer.expires_at(boost::asio::steady_timer::time_point::min()); { boost::system::error_code ec; @@ -192,7 +192,7 @@ Dictionary::Ptr EventsInbox::Shift(boost::asio::yield_context yc, double timeout } if (m_Queue.empty()) { - m_Timer.expires_from_now(boost::posix_time::milliseconds((unsigned long)(timeout * 1000.0))); + m_Timer.expires_after(timeout); lock.unlock(); { diff --git a/lib/remote/eventqueue.hpp b/lib/remote/eventqueue.hpp index 3a32142e463..b36c9abb04c 100644 --- a/lib/remote/eventqueue.hpp +++ b/lib/remote/eventqueue.hpp @@ -7,7 +7,7 @@ #include "remote/httphandler.hpp" #include "base/object.hpp" #include "config/expression.hpp" -#include +#include #include #include #include @@ -96,7 +96,7 @@ class EventsInbox : public Object const Expression::Ptr& GetFilter(); void Push(Dictionary::Ptr event); - Dictionary::Ptr Shift(boost::asio::yield_context yc, double timeout = 5); + Dictionary::Ptr Shift(boost::asio::yield_context yc, std::chrono::milliseconds timeout = 5s); private: struct Filter @@ -111,7 +111,7 @@ class EventsInbox : public Object std::mutex m_Mutex; decltype(m_Filters.begin()) m_Filter; std::queue m_Queue; - boost::asio::deadline_timer m_Timer; + boost::asio::steady_timer m_Timer; }; class EventsSubscriber diff --git a/lib/remote/httpserverconnection.cpp b/lib/remote/httpserverconnection.cpp index 07becaaf58c..b75a80a6a1d 100644 --- a/lib/remote/httpserverconnection.cpp +++ b/lib/remote/httpserverconnection.cpp @@ -561,7 +561,7 @@ void HttpServerConnection::CheckLiveness(boost::asio::yield_context yc) // Wait for the half of the liveness timeout to give the connection some leeway to do other work. // But never wait longer than 5 seconds to ensure timely shutdowns. auto sleepTime = std::min(5000ms, m_LivenessTimeout / 2); - m_CheckLivenessTimer.expires_from_now(boost::posix_time::milliseconds(sleepTime.count())); + m_CheckLivenessTimer.expires_after(sleepTime); m_CheckLivenessTimer.async_wait(yc[ec]); if (m_ShuttingDown) { diff --git a/lib/remote/httpserverconnection.hpp b/lib/remote/httpserverconnection.hpp index 4d352e5ade0..0048d88c048 100644 --- a/lib/remote/httpserverconnection.hpp +++ b/lib/remote/httpserverconnection.hpp @@ -9,7 +9,7 @@ #include "base/tlsstream.hpp" #include "base/wait-group.hpp" #include -#include +#include #include #include #include @@ -58,7 +58,7 @@ class HttpServerConnection final : public Object boost::asio::io_context::strand m_IoStrand; bool m_ShuttingDown; bool m_ConnectionReusable; - boost::asio::deadline_timer m_CheckLivenessTimer; + boost::asio::steady_timer m_CheckLivenessTimer; HttpServerConnection(const WaitGroup::Ptr& waitGroup, const String& identity, bool authenticated, const Shared::Ptr& stream, boost::asio::io_context& io); diff --git a/lib/remote/jsonrpcconnection-heartbeat.cpp b/lib/remote/jsonrpcconnection-heartbeat.cpp index faea591d97b..56e36e63305 100644 --- a/lib/remote/jsonrpcconnection-heartbeat.cpp +++ b/lib/remote/jsonrpcconnection-heartbeat.cpp @@ -27,7 +27,7 @@ void JsonRpcConnection::HandleAndWriteHeartbeats(boost::asio::yield_context yc) boost::system::error_code ec; for (;;) { - m_HeartbeatTimer.expires_from_now(boost::posix_time::seconds(20)); + m_HeartbeatTimer.expires_after(20s); m_HeartbeatTimer.async_wait(yc[ec]); if (m_ShuttingDown) { diff --git a/lib/remote/jsonrpcconnection.cpp b/lib/remote/jsonrpcconnection.cpp index 582c5f52642..d9d2482de63 100644 --- a/lib/remote/jsonrpcconnection.cpp +++ b/lib/remote/jsonrpcconnection.cpp @@ -263,7 +263,7 @@ void JsonRpcConnection::Disconnect() { Timeout writerTimeout( m_IoStrand, - boost::posix_time::seconds(5), + 5s, [this]() { // The writer coroutine could not finish soon enough to unblock the waiter down blow, // so we have to do this on our own, and the coroutine will be terminated forcibly when @@ -412,7 +412,7 @@ void JsonRpcConnection::CheckLiveness(boost::asio::yield_context yc) * leaking the connection. Therefore close it after a timeout. */ - m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(10)); + m_CheckLivenessTimer.expires_after(10s); m_CheckLivenessTimer.async_wait(yc[ec]); if (m_ShuttingDown) { @@ -427,7 +427,7 @@ void JsonRpcConnection::CheckLiveness(boost::asio::yield_context yc) Disconnect(); } else { for (;;) { - m_CheckLivenessTimer.expires_from_now(boost::posix_time::seconds(30)); + m_CheckLivenessTimer.expires_after(30s); m_CheckLivenessTimer.async_wait(yc[ec]); if (m_ShuttingDown) { diff --git a/lib/remote/jsonrpcconnection.hpp b/lib/remote/jsonrpcconnection.hpp index 78b64322bbd..ebfa0b55db9 100644 --- a/lib/remote/jsonrpcconnection.hpp +++ b/lib/remote/jsonrpcconnection.hpp @@ -82,7 +82,7 @@ class JsonRpcConnection final : public Object AsioEvent m_WriterDone; Atomic m_ShuttingDown; WaitGroup::Ptr m_WaitGroup; - boost::asio::deadline_timer m_CheckLivenessTimer, m_HeartbeatTimer; + boost::asio::steady_timer m_CheckLivenessTimer, m_HeartbeatTimer; JsonRpcConnection(const WaitGroup::Ptr& waitgroup, const String& identity, bool authenticated, const Shared::Ptr& stream, ConnectionRole role, boost::asio::io_context& io); diff --git a/test/base-io-engine.cpp b/test/base-io-engine.cpp index fce76342881..1e90b0fe360 100644 --- a/test/base-io-engine.cpp +++ b/test/base-io-engine.cpp @@ -19,16 +19,16 @@ BOOST_AUTO_TEST_CASE(timeout_run) int called = 0; IoEngine::SpawnCoroutine(strand, [&](boost::asio::yield_context yc) { - boost::asio::deadline_timer timer (io); + boost::asio::steady_timer timer (io); - Timeout timeout (strand, boost::posix_time::millisec(300), [&called] { ++called; }); + Timeout timeout (strand, 300ms, [&called] { ++called; }); BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); }); @@ -46,16 +46,16 @@ BOOST_AUTO_TEST_CASE(timeout_cancelled) int called = 0; IoEngine::SpawnCoroutine(strand, [&](boost::asio::yield_context yc) { - boost::asio::deadline_timer timer (io); - Timeout timeout (strand, boost::posix_time::millisec(300), [&called] { ++called; }); + boost::asio::steady_timer timer (io); + Timeout timeout (strand, 300ms, [&called] { ++called; }); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); timeout.Cancel(); BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); }); @@ -73,18 +73,18 @@ BOOST_AUTO_TEST_CASE(timeout_scope) int called = 0; IoEngine::SpawnCoroutine(strand, [&](boost::asio::yield_context yc) { - boost::asio::deadline_timer timer (io); + boost::asio::steady_timer timer (io); { - Timeout timeout (strand, boost::posix_time::millisec(300), [&called] { ++called; }); + Timeout timeout (strand, 300ms, [&called] { ++called; }); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); } BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(200)); + timer.expires_after(200ms); timer.async_wait(yc); }); @@ -102,8 +102,8 @@ BOOST_AUTO_TEST_CASE(timeout_due_cancelled) int called = 0; IoEngine::SpawnCoroutine(strand, [&](boost::asio::yield_context yc) { - boost::asio::deadline_timer timer (io); - Timeout timeout (strand, boost::posix_time::millisec(300), [&called] { ++called; }); + boost::asio::steady_timer timer (io); + Timeout timeout (strand, 300ms, [&called] { ++called; }); // Give the timeout enough time to become due while blocking its strand to prevent it from actually running... Utility::Sleep(0.4); @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(timeout_due_cancelled) BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(100)); + timer.expires_after(100ms); timer.async_wait(yc); }); @@ -133,10 +133,10 @@ BOOST_AUTO_TEST_CASE(timeout_due_scope) int called = 0; IoEngine::SpawnCoroutine(strand, [&](boost::asio::yield_context yc) { - boost::asio::deadline_timer timer (io); + boost::asio::steady_timer timer (io); { - Timeout timeout (strand, boost::posix_time::millisec(300), [&called] { ++called; }); + Timeout timeout (strand, 300ms, [&called] { ++called; }); // Give the timeout enough time to become due while blocking its strand to prevent it from actually running... Utility::Sleep(0.4); @@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(timeout_due_scope) BOOST_CHECK_EQUAL(called, 0); - timer.expires_from_now(boost::posix_time::millisec(100)); + timer.expires_after(100ms); timer.async_wait(yc); }); diff --git a/test/remote-httpserverconnection.cpp b/test/remote-httpserverconnection.cpp index 001aede3e63..19effa0182b 100644 --- a/test/remote-httpserverconnection.cpp +++ b/test/remote-httpserverconnection.cpp @@ -425,9 +425,9 @@ BOOST_AUTO_TEST_CASE(client_shutdown) response.StartStreaming(false); response.Flush(yc); - boost::asio::deadline_timer dt{IoEngine::Get().GetIoContext()}; + boost::asio::steady_timer dt{IoEngine::Get().GetIoContext()}; for (;;) { - dt.expires_from_now(boost::posix_time::seconds(1)); + dt.expires_after(1s); dt.async_wait(yc); if (!response.IsClientDisconnected()) {