From 8b383530122b972ca69cdac33427facf7b8aaadf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Jul 2025 16:47:14 +0200 Subject: eventloop: improve timer handling to avoid crashes ref #11062 --- src/managers/eventLoop/EventLoopManager.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/managers/eventLoop/EventLoopManager.cpp') diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 0389e7b8..b9ac7242 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -102,25 +102,25 @@ void CEventLoopManager::enterLoop() { void CEventLoopManager::onTimerFire() { const auto CPY = m_timers.timers; for (auto const& t : CPY) { - if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled()) + if (t.strongRef() > 2 /* if it's 2, it was lost. Don't call it. */ && t->passed() && !t->cancelled()) t->call(t); } - nudgeTimers(); + scheduleRecalc(); } void CEventLoopManager::addTimer(SP timer) { if (std::ranges::contains(m_timers.timers, timer)) return; m_timers.timers.emplace_back(timer); - nudgeTimers(); + scheduleRecalc(); } void CEventLoopManager::removeTimer(SP timer) { if (!std::ranges::contains(m_timers.timers, timer)) return; std::erase_if(m_timers.timers, [timer](const auto& t) { return timer == t; }); - nudgeTimers(); + scheduleRecalc(); } static void timespecAddNs(timespec* pTimespec, int64_t delta) { @@ -136,7 +136,21 @@ static void timespecAddNs(timespec* pTimespec, int64_t delta) { } } +void CEventLoopManager::scheduleRecalc() { + // do not do it instantly, do it later. Avoid recursive access to the timer + // vector, it could be catastrophic if we modify it while iterating + + if (m_timers.recalcScheduled) + return; + + m_timers.recalcScheduled = true; + + doLater([this] { nudgeTimers(); }); +} + void CEventLoopManager::nudgeTimers() { + m_timers.recalcScheduled = false; + // remove timers that have gone missing std::erase_if(m_timers.timers, [](const auto& t) { return t.strongRef() <= 1; }); -- cgit v1.2.3