22#include "fastmm/net/inplace_callback.hpp"
45 return static_cast<IoEvent>(
static_cast<std::uint32_t
>(a) |
static_cast<std::uint32_t
>(b));
48 return (
static_cast<std::uint32_t
>(set) &
static_cast<std::uint32_t
>(flag)) != 0;
75 using Task = std::function<void()>;
113 void wake() noexcept;
116 [[nodiscard]]
int wake_fd() const noexcept {
return wake_fd_; }
124 void run(
const std::atomic<bool>& stop);
129 void set_busy_poll(
bool enabled)
noexcept { busy_poll_ = enabled; }
138 after_event_ctx_ = ctx;
145 bool event_hangup() const noexcept {
return event_hangup_; }
147 static std::int64_t
now_ns() noexcept;
149 int epoll_fd() const noexcept {
return epoll_fd_; }
153 std::int64_t deadline_ns;
155 bool operator>(
const TimerEntry& o)
const noexcept {
156 return deadline_ns != o.deadline_ns ? deadline_ns > o.deadline_ns :
id > o.id;
161 std::uint32_t gen = 0;
162 std::uint32_t mask = 0;
163 std::uint64_t dev = 0;
164 std::uint64_t ino = 0;
167 void release() noexcept;
168 int compute_timeout_ms(
int max_wait_ms) const noexcept;
169 std::int64_t compute_timeout_ns(
int max_wait_ms) const noexcept;
170 void dispatch_io(
int nfds);
171 void deliver(
int fd, IoHandler* h,
bool error,
bool readable,
bool writable);
173 void run_expired_timers();
174 void drain_wake_fd() noexcept;
175 static
int socket_error(
int fd) noexcept;
178 int uring_run_once(
int max_wait_ms);
179 int uring_dispatch();
180 void uring_complete(std::uint64_t user_data, std::int32_t res, std::uint32_t flags);
181 bool uring_add(
int fd, IoHandler& handler,
IoEvent events) noexcept;
182 io_uring_sqe* uring_sqe() noexcept;
183 bool uring_arm(
int fd) noexcept;
184 bool uring_queue_update(
int fd, std::uint32_t mask) noexcept;
185 bool uring_queue_remove(
int fd, std::uint32_t gen) noexcept;
190 bool busy_poll_ = false;
191 bool event_hangup_ = false;
193 void* after_event_ctx_ =
nullptr;
194 std::vector<IoHandler*> handlers_;
198 static constexpr
unsigned kTimerSlotBits = 24;
199 static constexpr
TimerId kTimerSlotMask = (
TimerId{1} << kTimerSlotBits) - 1;
204 [[nodiscard]]
bool timer_live(
TimerId id)
const noexcept {
205 return timer_slots_[
id & kTimerSlotMask].id == id;
207 void release_timer_slot(std::size_t slot)
noexcept;
209 std::vector<TimerEntry> heap_;
210 std::vector<TimerSlot> timer_slots_;
211 std::vector<std::uint32_t> free_timer_slots_;
212 std::size_t active_timers_ = 0;
215 std::mutex post_mutex_;
216 std::atomic<bool> posted_pending_{
false};
217 std::vector<Task> posted_;
218 std::vector<Task> running_;
220 static constexpr int kMaxEvents = 64;
221 void* events_ =
nullptr;
223 std::unique_ptr<detail::IoUring> uring_;
224 std::vector<FdState> fd_state_;
Definition reactor.hpp:59
virtual void on_error(int err)=0
POLLERR (or a poll request the kernel refused).
virtual ~IoHandler()=default
virtual void on_readable()=0
virtual void on_writable()=0
Definition reactor.hpp:72
void wake() noexcept
Thread-safe: interrupt a blocking wait in run_once().
bool event_hangup() const noexcept
True while a handler runs for an event that also reported a hang-up or an error (RDHUP/HUP/ERR).
Definition reactor.hpp:146
void run(const std::atomic< bool > &stop)
Loop until stop becomes true (checked once per iteration; call wake() after setting it).
std::size_t active_timers() const noexcept
Definition reactor.hpp:109
bool is_registered(int fd) const noexcept
TimerId add_timer_after(std::int64_t delay_ns, TimerCallback cb)
Definition reactor.hpp:105
bool cancel_timer(TimerId id) noexcept
InplaceCallback TimerCallback
Stored inline (no heap): captures up to InplaceCallback::kCapacity bytes.
Definition reactor.hpp:75
bool add(int fd, IoHandler &handler, IoEvent events) noexcept
fd registration (reactor thread only).
Reactor()
Definition reactor.hpp:78
Reactor & operator=(const Reactor &)=delete
TimerId add_timer(std::int64_t deadline_ns, TimerCallback cb)
Timers (reactor thread only).
static bool io_uring_supported() noexcept
True when this kernel lets the process create an io_uring with everything the backend uses (multishot...
int epoll_fd() const noexcept
The epoll descriptor, or -1 with the io_uring backend.
Definition reactor.hpp:150
int run_once(int max_wait_ms)
One iteration: wait for I/O at most min(next timer, max_wait_ms), dispatch I/O, posted tasks,...
void set_after_event(EventHook fn, void *ctx) noexcept
Definition reactor.hpp:137
void set_busy_poll(bool enabled) noexcept
Busy polling: never block, pause instruction between empty polls.
Definition reactor.hpp:130
int wake_fd() const noexcept
The eventfd wake() writes.
Definition reactor.hpp:117
static ReactorBackend resolve_backend(ReactorBackend requested) noexcept
requested, or Epoll when io_uring was requested but is not supported.
bool modify(int fd, IoHandler &handler, IoEvent events) noexcept
std::function< void()> Task
Definition reactor.hpp:76
void post(Task task)
Thread-safe: queue a task for the reactor thread and wake it.
static std::int64_t now_ns() noexcept
CLOCK_MONOTONIC.
void(*)(void *ctx) EventHook
Called on the reactor thread after the handler of each I/O event, between one socket's event and the ...
Definition reactor.hpp:136
ReactorBackend backend() const noexcept
Definition reactor.hpp:86
bool remove(int fd) noexcept
bool busy_poll() const noexcept
Definition reactor.hpp:131
Definition reactor.hpp:37
constexpr IoEvent operator|(IoEvent a, IoEvent b) noexcept
Definition reactor.hpp:45
std::uint64_t TimerId
Definition reactor.hpp:69
std::string_view to_string(ReactorBackend backend) noexcept
"epoll" / "io_uring", the spelling of [engine] net_backend.
ReactorBackend
Definition reactor.hpp:52
constexpr bool has(IoEvent set, IoEvent flag) noexcept
Definition reactor.hpp:48
bool parse_reactor_backend(std::string_view text, ReactorBackend &out) noexcept
Parses "epoll" / "io_uring". Returns false (and leaves out alone) for anything else.
IoEvent
Definition reactor.hpp:43
constexpr TimerId kInvalidTimer
Definition reactor.hpp:70