diff --git a/lib/perfdata/perfdatawriterconnection.cpp b/lib/perfdata/perfdatawriterconnection.cpp index 4b0838d0a..8b50f061a 100644 --- a/lib/perfdata/perfdatawriterconnection.cpp +++ b/lib/perfdata/perfdatawriterconnection.cpp @@ -66,7 +66,7 @@ void PerfdataWriterConnection::Disconnect() return; } - std::promise promise; + SyncResult ret; IoEngine::SpawnCoroutine(m_Strand, [&](boost::asio::yield_context yc) { try { @@ -90,13 +90,13 @@ void PerfdataWriterConnection::Disconnect() m_ReconnectTimer.cancel(); Disconnect(std::move(yc)); - promise.set_value(); + ret.SetValue(); } catch (const std::exception& ex) { - promise.set_exception(std::current_exception()); + ret.SetException(std::current_exception()); } }); - promise.get_future().get(); + ret.Get(); } AsioTlsOrTcpStream PerfdataWriterConnection::MakeStream() const diff --git a/lib/perfdata/perfdatawriterconnection.hpp b/lib/perfdata/perfdatawriterconnection.hpp index 729878a29..9f91f037e 100644 --- a/lib/perfdata/perfdatawriterconnection.hpp +++ b/lib/perfdata/perfdatawriterconnection.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace icinga { @@ -21,6 +22,56 @@ class PerfdataWriterConnection final : public Object static constexpr auto InitialRetryWait = 50ms; static constexpr auto FinalRetryWait = 32s; + template + class SyncResult + { + using ValueType = std::variant, bool, T>, std::exception_ptr>; + + public: + template>> + void SetValue(U&& v) + { + std::lock_guard lock(m_Mutex); + m_Value = std::forward(v); + m_Cv.notify_one(); + } + + template>> + void SetValue() + { + std::lock_guard lock(m_Mutex); + m_Value = true; + m_Cv.notify_one(); + } + + void SetException(std::exception_ptr ep) + { + std::lock_guard lock(m_Mutex); + m_Value = ValueType{ep}; + m_Cv.notify_one(); + } + + T Get() + { + std::unique_lock l(m_Mutex); + m_Cv.wait(l, [&] { return !std::holds_alternative(m_Value); }); + if (std::holds_alternative(m_Value)) { + std::rethrow_exception(std::get(m_Value)); + } + + if constexpr (std::is_void_v) { + return; + } else { + return std::move(std::get(m_Value)); + } + } + + private: + std::mutex m_Mutex; + std::condition_variable m_Cv; + ValueType m_Value; + }; + public: DECLARE_PTR_TYPEDEFS(PerfdataWriterConnection); @@ -66,7 +117,7 @@ public: } using RetType = decltype(WriteMessage(std::declval(), std::declval())); - std::promise promise; + SyncResult ret; IoEngine::SpawnCoroutine(m_Strand, [&](boost::asio::yield_context yc) { while (true) { @@ -75,16 +126,16 @@ public: if constexpr (std::is_void_v) { WriteMessage(std::forward(buf), yc); - promise.set_value(); + ret.SetValue(); } else { - promise.set_value(WriteMessage(std::forward(buf), yc)); + ret.SetValue(WriteMessage(std::forward(buf), yc)); } m_RetryTimeout = InitialRetryWait; return; } catch (const std::exception& ex) { if (m_Stopped) { - promise.set_exception(std::make_exception_ptr(Stopped{})); + ret.SetException(std::make_exception_ptr(Stopped{})); return; } @@ -98,14 +149,14 @@ public: try { BackoffWait(yc); } catch (const std::exception&) { - promise.set_exception(std::make_exception_ptr(Stopped{})); + ret.SetException(std::make_exception_ptr(Stopped{})); return; } } } }); - return promise.get_future().get(); + return ret.Get(); } void Disconnect();