#pragma once // A single-threaded poll(2) reactor. Every RPC listener and connection registers its fd // here; the loop never blocks on disk or DNS (AGENT-DAEMON.md build step 1 — "Never block // the RPC loop"). Long work is handed to CORE's pools later; this class only multiplexes // readiness. // // Thread model: run() executes on one thread. add_fd/mod_fd/del_fd are called from // callbacks on that same thread. stop() and wake() are async-signal-safe and safe to call // from any thread or a signal handler — they only write() a byte to an internal eventfd. #include #include #include #include #include #include namespace velox::daemon::rpc { enum Interest : unsigned { kNone = 0, kRead = 1u << 0, kWrite = 1u << 1, }; class EventLoop { public: // Called when the fd is readable and/or writable. `events` is the subset of the fd's // registered Interest that fired. A callback may add/modify/remove any fd, including // its own, and may call stop(). using Callback = std::function; EventLoop(); ~EventLoop(); EventLoop(const EventLoop&) = delete; EventLoop& operator=(const EventLoop&) = delete; // Register `fd` (must be non-blocking) for `interest`. Replaces any prior registration. void add_fd(int fd, unsigned interest, Callback cb); // Change the interest mask for an already-registered fd. void mod_fd(int fd, unsigned interest); // Stop watching `fd`. Does not close it — ownership stays with the caller. void del_fd(int fd); // Run until stop() is called. Re-entrant calls are not supported. void run(); // Ask run() to return after the current poll wakeup. Async-signal-safe. void stop() noexcept; // Force one poll() wakeup without stopping — used when interest changed from outside a // callback. Async-signal-safe. void wake() noexcept; // Run `fn` on the loop thread at the next iteration. Thread-safe; the intended way to // marshal an engine-thread callback back onto the RPC loop. void post(std::function fn); private: struct Entry { unsigned interest; Callback cb; }; void drain_wakeup() noexcept; void drain_posts(); int wake_fd_; // eventfd, always registered bool running_ = false; std::atomic stop_requested_ = false; // set from stop(), read by run() std::unordered_map fds_; std::mutex post_mu_; std::vector> posts_; }; } // namespace velox::daemon::rpc