summaryrefslogtreecommitdiff
path: root/src/managers/eventLoop/EventLoopManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/managers/eventLoop/EventLoopManager.cpp')
-rw-r--r--src/managers/eventLoop/EventLoopManager.cpp140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp
new file mode 100644
index 00000000..0dabdcfb
--- /dev/null
+++ b/src/managers/eventLoop/EventLoopManager.cpp
@@ -0,0 +1,140 @@
+#include "EventLoopManager.hpp"
+#include "../../debug/Log.hpp"
+
+#include <algorithm>
+
+#include <sys/poll.h>
+
+void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoop) {
+ m_sWayland.loop = wlEventLoop;
+ m_sWayland.display = display;
+
+ pollfd pollfds[] = {
+ {
+ .fd = wl_event_loop_get_fd(wlEventLoop),
+ .events = POLLIN,
+ },
+ };
+
+ std::thread pollThr([this, &pollfds]() {
+ while (!m_bTerminate) {
+ int ret = poll(pollfds, 1, 5000 /* 5 seconds, reasonable. Just in case we need to terminate and the signal fails */);
+
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+
+ Debug::log(CRIT, "Polling fds failed with {}", errno);
+ m_bTerminate = true;
+ return;
+ }
+
+ for (size_t i = 0; i < 1; ++i) {
+ if (pollfds[i].revents & POLLHUP) {
+ Debug::log(CRIT, "Disconnected from pollfd id {}", i);
+ m_bTerminate = true;
+ return;
+ }
+ }
+
+ if (ret != 0) {
+ {
+ std::lock_guard<std::mutex> lg2(m_sLoopState.eventRequestMutex);
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+ m_sLoopState.event = true;
+ }
+ m_sLoopState.cv.notify_all();
+ }
+ }
+ });
+
+ std::thread timersThr([this]() {
+ while (!m_bTerminate) {
+ // calc nearest thing
+
+ m_sTimers.timersMutex.lock();
+ float least = 1000 * 1000 * 10; // 10s in µs
+ for (auto& t : m_sTimers.timers) {
+ const auto TIME = std::clamp(t->leftUs(), 0.f, INFINITY);
+ if (TIME < least)
+ least = TIME;
+ }
+ m_sTimers.timersMutex.unlock();
+
+ if (least > 0) {
+ std::unique_lock lk(m_sTimers.timersRqMutex);
+ m_sTimers.cv.wait_for(lk, std::chrono::microseconds((int)least + 1), [this] { return m_sTimers.event; });
+ m_sTimers.event = false;
+ }
+
+ // notify main
+ {
+ std::lock_guard<std::mutex> lg2(m_sLoopState.eventRequestMutex);
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+ m_sLoopState.event = true;
+ }
+
+ m_sLoopState.cv.notify_all();
+ }
+ });
+
+ m_sLoopState.event = true; // let it process once
+
+ while (1) {
+ std::unique_lock lk(m_sLoopState.eventRequestMutex);
+ m_sLoopState.cv.wait_for(lk, std::chrono::milliseconds(5000), [this] { return m_sLoopState.event; });
+
+ if (m_bTerminate)
+ break;
+
+ std::lock_guard<std::mutex> lg(m_sLoopState.loopMutex);
+
+ m_sLoopState.event = false;
+
+ if (pollfds[0].revents & POLLIN /* wl event loop */) {
+ wl_display_flush_clients(m_sWayland.display);
+ if (wl_event_loop_dispatch(m_sWayland.loop, -1) < 0) {
+ m_bTerminate = true;
+ break;
+ }
+ }
+
+ // TODO: don't check timers without the timer thread requesting it
+ // I tried but it didnt work :/
+
+ m_sTimers.timersMutex.lock();
+ auto timerscpy = m_sTimers.timers;
+ m_sTimers.timersMutex.unlock();
+
+ for (auto& t : timerscpy) {
+ if (t->passed() && !t->cancelled())
+ t->call(t);
+ }
+
+ if (m_bTerminate)
+ break;
+ }
+
+ Debug::log(LOG, "Kicked off the event loop! :(");
+
+ m_sTimers.event = true;
+ m_sTimers.cv.notify_all();
+}
+
+void CEventLoopManager::addTimer(std::shared_ptr<CEventLoopTimer> timer) {
+ m_sTimers.timersMutex.lock();
+ m_sTimers.timers.push_back(timer);
+ m_sTimers.timersMutex.unlock();
+ nudgeTimers();
+}
+
+void CEventLoopManager::removeTimer(std::shared_ptr<CEventLoopTimer> timer) {
+ m_sTimers.timersMutex.lock();
+ std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; });
+ m_sTimers.timersMutex.unlock();
+}
+
+void CEventLoopManager::nudgeTimers() {
+ m_sTimers.event = true;
+ m_sTimers.cv.notify_all();
+} \ No newline at end of file