summaryrefslogtreecommitdiff
path: root/src/managers/eventLoop
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
parent3b04131259bad140183a3825b981ebe30b61e524 (diff)
eventloop: improve timer handling to avoid crashes
ref #11062
Diffstat (limited to 'src/managers/eventLoop')
-rw-r--r--src/managers/eventLoop/EventLoopManager.cpp22
-rw-r--r--src/managers/eventLoop/EventLoopManager.hpp6
-rw-r--r--src/managers/eventLoop/EventLoopTimer.cpp4
3 files changed, 24 insertions, 8 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; });
diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp
index 0835b242..d3a67ae5 100644
--- a/src/managers/eventLoop/EventLoopManager.hpp
+++ b/src/managers/eventLoop/EventLoopManager.hpp
@@ -27,8 +27,8 @@ class CEventLoopManager {
void onTimerFire();
- // recalculates timers
- void nudgeTimers();
+ // schedules a recalc of the timers
+ void scheduleRecalc();
// schedules a function to run later, aka in a wayland idle event.
void doLater(const std::function<void()>& fn);
@@ -69,6 +69,7 @@ class CEventLoopManager {
private:
// Manages the event sources after AQ pollFDs change.
void syncPollFDs();
+ void nudgeTimers();
struct SEventSourceData {
SP<Aquamarine::SPollFD> pollFD;
@@ -84,6 +85,7 @@ class CEventLoopManager {
struct {
std::vector<SP<CEventLoopTimer>> timers;
Hyprutils::OS::CFileDescriptor timerfd;
+ bool recalcScheduled = false;
} m_timers;
SIdleData m_idle;
diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp
index d4633b0d..fa86c861 100644
--- a/src/managers/eventLoop/EventLoopTimer.cpp
+++ b/src/managers/eventLoop/EventLoopTimer.cpp
@@ -14,13 +14,13 @@ CEventLoopTimer::CEventLoopTimer(std::optional<Time::steady_dur> timeout, std::f
void CEventLoopTimer::updateTimeout(std::optional<Time::steady_dur> timeout) {
if (!timeout.has_value()) {
m_expires.reset();
- g_pEventLoopManager->nudgeTimers();
+ g_pEventLoopManager->scheduleRecalc();
return;
}
m_expires = Time::steadyNow() + *timeout;
- g_pEventLoopManager->nudgeTimers();
+ g_pEventLoopManager->scheduleRecalc();
}
bool CEventLoopTimer::passed() {