/** * @file EventLoop.h * @author apio (cloudapio.eu) * @brief Base class for event-driven applications. * * @copyright Copyright (c) 2023-2024, the Luna authors. * */ #pragma once #include <luna/HashMap.h> #include <luna/Vector.h> #include <os/Action.h> #include <os/Timer.h> #include <sys/poll.h> namespace os { /** * @brief Event loop implementation. */ class EventLoop { public: /** * @brief Construct a new event loop, which will automatically register itself as the current global event loop. */ EventLoop(); ~EventLoop(); EventLoop(EventLoop&&) = delete; EventLoop(const EventLoop&) = delete; /** * @brief Fetch the current global event loop. * * @return EventLoop& The current global event loop. */ static EventLoop& the(); /** * @brief Register a new event listener on a file descriptor. * * @param fd The file descriptor to listen on. * @param listener The callback function to invoke when events occur on the file descriptor. The first parameter * is the file descriptor registered, and the second argument is the type of event (POLLIN or POLLHUP) * @return Result<void> Whether the operation succeeded. */ Result<void> register_fd_listener(int fd, Function<int, int> listener); /** * @brief Register a new POSIX signal handler. * * Unlike standard POSIX signal handling, this handler will be run synchronously as part of the event loop, * eliminating many problems with asynchronous signal handling. * * @param sig The signal to handle. * @param handler The function to call when this signal is caught. * @return Result<void> Whether the operation succeeded. */ Result<void> register_signal_handler(int sig, Function<int> handler); /** * @brief Run the event loop until it is asked to quit. * * @return int The status passed to the quit() method. */ int run(); /** * @brief Ask the event loop to quit. * * @param status The status value to return from run(). */ void quit(int status = 0); private: HashMap<int, Function<int, int>> m_fd_listeners; HashMap<int, Function<int>> m_signal_handlers; Vector<struct pollfd> m_pollfds; static void handle_signal(int sig); static void handle_quit_signal(int); static void handle_timer_signal(int); bool m_should_quit { false }; int m_quit_status { 0 }; int m_signal_pipe[2]; LinkedList<Timer> m_timer_list; friend class Timer; }; }