Hyprland/src/managers/eventLoop/EventLoopManager.cpp
Tom Englund 5489682799
internal: some minor fd/socket cleanups and make logging thread safe (#7123)
* bezier: dont loop on float values

Using a floating-point loop variable with a fixed increment can cause precision
errors over time due to the nature of floating-point arithmetic.
and cause undesired effects.

ex
iteration 1 = 0.10000000149011611938
iteration 2 = 0.20000000298023223877

eventually..

iteration 8 = 0.80000001192092895508
iteration 9 = 0.89999997615814208984

* hyprctl: close sockets on destruction

store socketpath and close the fd and unlink the socket path on exit.

* eventloopmgr: close the timerfd

close the timerfd on exit.

* debug: make logging thread safe

instead of opening and closing the logfile on each write open it on init
and close it on compositor exit. also add a mutex so accidently using
logging from a thread like the watchdog or similiar doesnt cause issues.

* xwl: clean up fd logic

check if the fd is actually opened before closing, and close the
pipesource FD on exit.
2024-07-31 21:00:14 +02:00

132 lines
3.8 KiB
C++

#include "EventLoopManager.hpp"
#include "../../debug/Log.hpp"
#include "../../Compositor.hpp"
#include <algorithm>
#include <limits>
#include <sys/timerfd.h>
#include <time.h>
#include <aquamarine/backend/Backend.hpp>
#define TIMESPEC_NSEC_PER_SEC 1000000000L
CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) {
m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
m_sWayland.loop = wlEventLoop;
m_sWayland.display = display;
}
CEventLoopManager::~CEventLoopManager() {
for (auto& eventSource : m_sWayland.aqEventSources) {
wl_event_source_remove(eventSource);
}
if (m_sWayland.eventSource)
wl_event_source_remove(m_sWayland.eventSource);
if (m_sIdle.eventSource)
wl_event_source_remove(m_sIdle.eventSource);
if (m_sTimers.timerfd >= 0)
close(m_sTimers.timerfd);
}
static int timerWrite(int fd, uint32_t mask, void* data) {
g_pEventLoopManager->onTimerFire();
return 1;
}
static int aquamarineFDWrite(int fd, uint32_t mask, void* data) {
auto POLLFD = (Aquamarine::SPollFD*)data;
POLLFD->onSignal();
return 1;
}
void CEventLoopManager::enterLoop() {
m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs();
for (auto& fd : aqPollFDs) {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()));
fd->onSignal(); // dispatch outstanding
}
wl_display_run(m_sWayland.display);
Debug::log(LOG, "Kicked off the event loop! :(");
}
void CEventLoopManager::onTimerFire() {
for (auto& t : m_sTimers.timers) {
if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled())
t->call(t);
}
nudgeTimers();
}
void CEventLoopManager::addTimer(SP<CEventLoopTimer> timer) {
m_sTimers.timers.push_back(timer);
nudgeTimers();
}
void CEventLoopManager::removeTimer(SP<CEventLoopTimer> timer) {
std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; });
nudgeTimers();
}
static void timespecAddNs(timespec* pTimespec, int64_t delta) {
int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC;
int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC;
pTimespec->tv_sec += delta_s_high;
pTimespec->tv_nsec += (long)delta_ns_low;
if (pTimespec->tv_nsec >= TIMESPEC_NSEC_PER_SEC) {
pTimespec->tv_nsec -= TIMESPEC_NSEC_PER_SEC;
++pTimespec->tv_sec;
}
}
void CEventLoopManager::nudgeTimers() {
// remove timers that have gone missing
std::erase_if(m_sTimers.timers, [](const auto& t) { return t.strongRef() <= 1; });
long nextTimerUs = 10 * 1000 * 1000; // 10s
for (auto& t : m_sTimers.timers) {
if (const auto µs = t->leftUs(); µs < nextTimerUs)
nextTimerUs = µs;
}
nextTimerUs = std::clamp(nextTimerUs + 1, 1L, std::numeric_limits<long>::max());
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
timespecAddNs(&now, nextTimerUs * 1000L);
itimerspec ts = {.it_value = now};
timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr);
}
void CEventLoopManager::doLater(const std::function<void()>& fn) {
m_sIdle.fns.emplace_back(fn);
if (m_sIdle.eventSource)
return;
m_sIdle.eventSource = wl_event_loop_add_idle(
m_sWayland.loop,
[](void* data) {
auto IDLE = (CEventLoopManager::SIdleData*)data;
auto cpy = IDLE->fns;
IDLE->fns.clear();
IDLE->eventSource = nullptr;
for (auto& c : cpy) {
if (c)
c();
}
},
&m_sIdle);
}