eventloop: improve timer handling to avoid crashes

ref #11062
This commit is contained in:
Vaxry
2025-07-19 16:47:14 +02:00
parent 3b04131259
commit 8b38353012
3 changed files with 24 additions and 8 deletions

View File

@@ -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; });

View File

@@ -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;

View File

@@ -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() {