Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #pragma once
16 : :
17 : : #include <hpactor/net/reactor_backend.hpp>
18 : :
19 : : #include <atomic>
20 : : #include <functional>
21 : : #include <memory>
22 : : #include <unordered_map>
23 : : #include <unordered_set>
24 : :
25 : : namespace hpactor {
26 : :
27 : : class ActorSystem;
28 : :
29 : : namespace net {
30 : :
31 : : class ProactorDispatcher;
32 : :
33 : : // -----------------------------------------------------------------------------
34 : : // EventLoop - async I/O backend wrapper
35 : : // -----------------------------------------------------------------------------
36 : : // Provides a unified interface over platform-specific async I/O backends:
37 : : // - io_uring on Linux (preferred), epoll fallback
38 : : // - libdispatch (GCD) on macOS (preferred), kqueue fallback
39 : : //
40 : : // Usage:
41 : : // EventLoop loop; // Creates backend but doesn't start
42 : : // loop.run(); // Explicitly start processing
43 : : // // ... event loop runs ...
44 : : // loop.stop(); // Stop when done
45 : : // -----------------------------------------------------------------------------
46 : : class EventLoop {
47 : : public:
48 : : EventLoop();
49 : : ~EventLoop();
50 : :
51 : : // Non-copyable, non-movable
52 : : EventLoop(const EventLoop&) = delete;
53 : : EventLoop& operator=(const EventLoop&) = delete;
54 : : EventLoop(EventLoop&&) = delete;
55 : : EventLoop& operator=(EventLoop&&) = delete;
56 : :
57 : : // Start the backend and begin processing events
58 : : // Call this explicitly after construction
59 : : bool run();
60 : :
61 : : // Stop the backend
62 : : void stop();
63 : :
64 : : // Check if the backend is running
65 : 18 : bool is_running() const {
66 : 18 : return running_.load();
67 : : }
68 : :
69 : : // Get the backend name for debugging
70 : : const char* backend_name() const;
71 : :
72 : : // File descriptor registration
73 : : enum class Event : uint32_t {
74 : : Read = 1,
75 : : Write = 2,
76 : : EdgeTriggered = 4,
77 : : };
78 : :
79 : : // Add or update a file descriptor interest
80 : : bool add_fd(int fd, Event events);
81 : :
82 : : // Update an existing fd registration
83 : : bool update_fd(int fd, Event events);
84 : :
85 : : // Remove an fd registration
86 : : bool remove_fd(int fd);
87 : :
88 : : // Read handler callback type (re-exported from async_io_fwd.hpp)
89 : : using read_callback = net::read_callback;
90 : :
91 : : // Set a read handler for an FD. When data arrives, it's delivered to this
92 : : // callback. The EventLoop will automatically issue async_recv for the FD
93 : : // when it becomes readable.
94 : : void set_read_handler(int fd, read_callback handler);
95 : :
96 : : // Remove read handler for an FD
97 : : void clear_read_handler(int fd);
98 : :
99 : : // Returns true if the backend supports calling read handlers directly
100 : : // from wait(). Reactor backends return true, proactor return false.
101 : : bool supports_read_handler() const;
102 : :
103 : : // Set a write handler for an FD. When the fd becomes writable, the
104 : : // callback is invoked. Used for non-blocking connect completion.
105 : : void set_write_handler(int fd, write_callback handler);
106 : :
107 : : // Remove write handler for an FD
108 : : void clear_write_handler(int fd);
109 : :
110 : : // Returns true if the backend supports write handler dispatch
111 : : bool supports_write_handler() const;
112 : :
113 : : // Wait for events (blocking with timeout)
114 : : // Returns number of events triggered, 0 on timeout, -1 on error
115 : : int wait(int timeout_ms);
116 : :
117 : : // Get triggered events for an fd
118 : : bool has_event(int fd, Event event) const;
119 : :
120 : : // Timer callback type
121 : : using timer_callback = std::function<void()>;
122 : :
123 : : // Schedule a one-shot timer to fire after delay_ms milliseconds
124 : : // Returns a timer handle that can be used to cancel the timer
125 : : uint64_t run_after(timer_callback callback, int delay_ms);
126 : :
127 : : // Schedule a repeating timer to fire every interval_ms milliseconds
128 : : // Returns a timer handle that can be used to cancel the timer
129 : : uint64_t run_every(timer_callback callback, int interval_ms);
130 : :
131 : : // Cancel a scheduled timer
132 : : void cancel_timer(uint64_t timer_handle);
133 : :
134 : : // Process completions from the backend (called by wait loop)
135 : : void process_completions();
136 : :
137 : : // Enqueue a completion to be delivered to an actor
138 : : // Called by proactor backend via its deliver_completion
139 : : void enqueue_completion(OpCompletion completion);
140 : :
141 : : // Set the ActorSystem for delivering completions
142 : : void set_actor_system(ActorSystem* actor_system);
143 : :
144 : : // Set callback for test verification (test-only API)
145 : : using completion_callback = std::function<void(OpCompletion)>;
146 : 20 : void set_completion_callback(completion_callback cb) {
147 : 20 : completion_callback_ = std::move(cb);
148 : 20 : }
149 : :
150 : : // Get the underlying backend for direct async operations
151 : 11 : IReactorBackend* backend() {
152 : 11 : return backend_.get();
153 : : }
154 : :
155 : : private:
156 : : // Deliver a timer completion to the stored callback
157 : : void deliver_timer_completion(OpCompletion completion);
158 : :
159 : : std::unique_ptr<IReactorBackend> backend_;
160 : : std::unique_ptr<ProactorDispatcher> proactor_dispatcher_;
161 : : std::atomic<bool> running_{false};
162 : : const char* backend_name_ = "unknown";
163 : :
164 : : // Map timer handles to callbacks (for bridging backend completions to
165 : : // callbacks)
166 : : std::unordered_map<uint64_t, timer_callback> timer_callbacks_;
167 : : std::atomic<uint64_t> next_timer_handle_{1};
168 : :
169 : : // Map backend timer handles to our timer handles
170 : : std::unordered_map<uint64_t, uint64_t> backend_handle_to_handle_;
171 : :
172 : : // Set of timer handles that are repeating (run_every)
173 : : std::unordered_set<uint64_t> repeating_timers_;
174 : :
175 : : // For has_event tracking
176 : : std::unordered_map<int, Event> fd_events_;
177 : :
178 : : // Optional callback for test verification (disabled in production)
179 : : completion_callback completion_callback_;
180 : :
181 : : ActorSystem* actor_system_ = nullptr;
182 : : };
183 : :
184 : : } // namespace net
185 : : } // namespace hpactor
|