2023-10-06 20:06:34 +00:00
|
|
|
/**
|
|
|
|
* @file EventLoop.cpp
|
|
|
|
* @author apio (cloudapio.eu)
|
|
|
|
* @brief Base class for event-driven applications.
|
|
|
|
*
|
2024-01-05 21:16:50 +00:00
|
|
|
* @copyright Copyright (c) 2023-2024, the Luna authors.
|
2023-10-06 20:06:34 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <os/EventLoop.h>
|
|
|
|
#include <os/File.h>
|
2023-10-07 12:26:35 +00:00
|
|
|
#include <signal.h>
|
2023-10-06 20:06:34 +00:00
|
|
|
#include <string.h>
|
2023-11-16 20:58:45 +00:00
|
|
|
#include <sys/time.h>
|
2023-10-09 20:00:15 +00:00
|
|
|
#include <time.h>
|
2023-10-07 12:26:35 +00:00
|
|
|
#include <unistd.h>
|
2023-10-06 20:06:34 +00:00
|
|
|
|
|
|
|
static os::EventLoop* s_the = nullptr;
|
|
|
|
|
|
|
|
namespace os
|
|
|
|
{
|
|
|
|
EventLoop::EventLoop()
|
|
|
|
{
|
|
|
|
s_the = this;
|
2023-10-07 12:26:35 +00:00
|
|
|
|
|
|
|
// Set up synchronous signal handling.
|
|
|
|
check(pipe(m_signal_pipe) == 0);
|
|
|
|
m_pollfds.try_append({ .fd = m_signal_pipe[0], .events = POLLIN, .revents = 0 }).release_value();
|
|
|
|
|
|
|
|
register_signal_handler(SIGTERM, EventLoop::handle_quit_signal).release_value();
|
|
|
|
register_signal_handler(SIGINT, EventLoop::handle_quit_signal).release_value();
|
2023-10-09 20:00:15 +00:00
|
|
|
register_signal_handler(SIGALRM, EventLoop::handle_timer_signal).release_value();
|
2023-10-06 20:06:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EventLoop::~EventLoop()
|
|
|
|
{
|
|
|
|
s_the = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
EventLoop& EventLoop::the()
|
|
|
|
{
|
|
|
|
check(s_the);
|
|
|
|
return *s_the;
|
|
|
|
}
|
|
|
|
|
2024-01-18 19:52:36 +00:00
|
|
|
Result<void> EventLoop::register_fd_listener(int fd, Function<int, int> listener)
|
2023-10-06 20:06:34 +00:00
|
|
|
{
|
2024-01-18 19:52:36 +00:00
|
|
|
TRY(m_fd_listeners.try_set(fd, move(listener)));
|
2023-10-06 20:06:34 +00:00
|
|
|
TRY(m_pollfds.try_append({ .fd = fd, .events = POLLIN, .revents = 0 }));
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2024-01-18 19:52:36 +00:00
|
|
|
Result<void> EventLoop::register_signal_handler(int sig, Function<int> handler)
|
2023-10-07 12:26:35 +00:00
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = EventLoop::handle_signal;
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
check(sigaction(sig, &sa, nullptr) == 0);
|
|
|
|
|
2024-01-18 19:52:36 +00:00
|
|
|
TRY(m_signal_handlers.try_set(sig, move(handler)));
|
2023-10-07 12:26:35 +00:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-10-06 20:06:34 +00:00
|
|
|
int EventLoop::run()
|
|
|
|
{
|
|
|
|
while (!m_should_quit)
|
|
|
|
{
|
|
|
|
for (auto& pfd : m_pollfds) { pfd.revents = 0; }
|
|
|
|
|
|
|
|
int rc = poll(m_pollfds.data(), m_pollfds.size(), 1000);
|
|
|
|
if (!rc) continue;
|
|
|
|
if (rc < 0 && errno != EINTR)
|
|
|
|
{
|
|
|
|
os::println("poll: error: %s", strerror(errno));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-10-07 12:26:35 +00:00
|
|
|
if (m_pollfds[0].revents & POLLIN)
|
|
|
|
{
|
|
|
|
int sig;
|
|
|
|
read(m_signal_pipe[0], &sig, sizeof(int));
|
|
|
|
|
|
|
|
auto handler = m_signal_handlers.try_get(sig);
|
2024-01-18 19:52:36 +00:00
|
|
|
if (handler.has_value()) { (*handler.value_ptr())(sig); }
|
2023-10-07 12:26:35 +00:00
|
|
|
}
|
|
|
|
|
2023-10-06 20:06:34 +00:00
|
|
|
for (usize i = 0; i < m_fd_listeners.size(); i++)
|
|
|
|
{
|
2023-10-07 12:26:35 +00:00
|
|
|
auto& pfd = m_pollfds[i + 1];
|
|
|
|
if (pfd.revents)
|
|
|
|
{
|
|
|
|
auto handler = m_fd_listeners.try_get(pfd.fd);
|
2024-01-18 19:52:36 +00:00
|
|
|
if (handler.has_value()) (*handler.value_ptr())(pfd.fd, pfd.revents);
|
2023-10-07 12:26:35 +00:00
|
|
|
}
|
2023-10-06 20:06:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_quit_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EventLoop::quit(int status)
|
|
|
|
{
|
|
|
|
m_quit_status = status;
|
|
|
|
m_should_quit = true;
|
|
|
|
}
|
2023-10-07 12:26:35 +00:00
|
|
|
|
|
|
|
void EventLoop::handle_signal(int sig)
|
|
|
|
{
|
|
|
|
write(the().m_signal_pipe[1], &sig, sizeof(int));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EventLoop::handle_quit_signal(int sig)
|
|
|
|
{
|
|
|
|
os::println("EventLoop: quit requested by signal %d", sig);
|
|
|
|
the().quit(sig);
|
|
|
|
}
|
2023-10-09 20:00:15 +00:00
|
|
|
|
|
|
|
void EventLoop::handle_timer_signal(int)
|
|
|
|
{
|
2024-01-05 21:16:50 +00:00
|
|
|
auto& queue = the().m_timer_list;
|
|
|
|
queue.delayed_for_each([](Timer* t) { t->check_if_should_invoke_action(); });
|
2023-10-09 20:00:15 +00:00
|
|
|
}
|
2023-10-06 20:06:34 +00:00
|
|
|
}
|