From 1badbab0023ba19dc7e76a53dd00a027f7316038 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 21 Mar 2023 11:45:47 +0100 Subject: [PATCH] Timer::TimerThreadProc(): keep a Timer alive while it's running to prevent the case: Timer callback destroys parent object -> destroys Timer -> ~Timer() -> Stop(true) -> waits for the Timer callback to finish -> deadlock. --- lib/base/timer.cpp | 19 ++++++++++++++++++- lib/base/timer.hpp | 7 ++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/base/timer.cpp b/lib/base/timer.cpp index 4de5d7e0e..bdeb0f277 100644 --- a/lib/base/timer.cpp +++ b/lib/base/timer.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace icinga; @@ -61,6 +62,15 @@ static int l_AliveTimers = 0; static Defer l_ShutdownTimersCleanlyOnExit (&Timer::Uninitialize); +Timer::Ptr Timer::Create() +{ + Ptr t (new Timer()); + + t->m_Self = t; + + return t; +} + /** * Destructor for the Timer class. */ @@ -316,11 +326,18 @@ void Timer::TimerThreadProc() * until the current call is completed. */ l_Timers.erase(timer); + auto keepAlive (timer->m_Self.lock()); + + if (!keepAlive) { + // The last std::shared_ptr is gone, let ~Timer() proceed + continue; + } + timer->m_Running = true; lock.unlock(); /* Asynchronously call the timer. */ - Utility::QueueAsyncCallback([timer]() { timer->Call(); }); + Utility::QueueAsyncCallback([timer=std::move(keepAlive)]() { timer->Call(); }); } } diff --git a/lib/base/timer.hpp b/lib/base/timer.hpp index 29625a358..a90963509 100644 --- a/lib/base/timer.hpp +++ b/lib/base/timer.hpp @@ -21,11 +21,7 @@ class Timer final public: typedef std::shared_ptr Ptr; - static inline - Ptr Create() - { - return Ptr(new Timer()); - } + static Ptr Create(); ~Timer(); @@ -52,6 +48,7 @@ private: double m_Next{0}; /**< When the next event should happen. */ bool m_Started{false}; /**< Whether the timer is enabled. */ bool m_Running{false}; /**< Whether the timer proc is currently running. */ + std::weak_ptr m_Self; Timer() = default; void Call();