summaryrefslogtreecommitdiff
path: root/src/managers/eventLoop/EventLoopManager.cpp
diff options
context:
space:
mode:
authorVaxry <vaxry@vaxry.net>2025-07-19 16:47:14 +0200
committerVaxry <vaxry@vaxry.net>2025-07-19 16:47:14 +0200
commit8b383530122b972ca69cdac33427facf7b8aaadf (patch)
tree177c7920cedd987f758fcc0d73b086a35aca7f8c /src/managers/eventLoop/EventLoopManager.cpp
parent3b04131259bad140183a3825b981ebe30b61e524 (diff)
eventloop: improve timer handling to avoid crashes
ref #11062
Diffstat (limited to 'src/managers/eventLoop/EventLoopManager.cpp')
-rw-r--r--src/managers/eventLoop/EventLoopManager.cpp22
1 files changed, 18 insertions, 4 deletions
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<CEventLoopTimer> timer) {
if (std::ranges::contains(m_timers.timers, timer))
return;
m_timers.timers.emplace_back(timer);
- nudgeTimers();
+ scheduleRecalc();
}
void CEventLoopManager::removeTimer(SP<CEventLoopTimer> 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; });