TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
3 : // Copyright (c) 2026 Michael Vandeberg
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
12 : #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
13 :
14 : #include <boost/corosio/io_context.hpp>
15 : #include <boost/corosio/backend.hpp>
16 :
17 : #ifndef BOOST_COROSIO_MRDOCS
18 : #if BOOST_COROSIO_HAS_EPOLL
19 : #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
20 : #endif
21 :
22 : #if BOOST_COROSIO_HAS_SELECT
23 : #include <boost/corosio/native/detail/select/select_scheduler.hpp>
24 : #endif
25 :
26 : #if BOOST_COROSIO_HAS_KQUEUE
27 : #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp>
28 : #endif
29 :
30 : #if BOOST_COROSIO_HAS_IOCP
31 : #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
32 : #endif
33 :
34 : #if BOOST_COROSIO_HAS_URING
35 : #include <boost/corosio/native/detail/uring/uring_scheduler.hpp>
36 : #endif
37 : #endif // !BOOST_COROSIO_MRDOCS
38 :
39 : namespace boost::corosio {
40 :
41 : /** Runs asynchronous operations, calling the backend event loop directly.
42 :
43 : This class template inherits from @ref io_context and shadows
44 : all public methods with versions that call the concrete
45 : scheduler directly, bypassing virtual dispatch. No new state
46 : is added.
47 :
48 : A `native_io_context` IS-A `io_context` and can be passed
49 : anywhere an `io_context&` is accepted. In that case, virtual
50 : dispatch is used transparently.
51 :
52 : @tparam Backend A backend tag value (e.g., `epoll`,
53 : `iocp`) whose type provides `scheduler_type`.
54 :
55 : @par Thread Safety
56 : Same as the underlying context type.
57 :
58 : @par Example
59 : @par !example poll
60 :
61 : @see @ref io_context, @ref epoll_t, @ref iocp_t
62 : */
63 : template<auto Backend>
64 : class native_io_context : public io_context
65 : {
66 : using backend_type = decltype(Backend);
67 : using scheduler_type = typename backend_type::scheduler_type;
68 :
69 HIT 219 : scheduler_type& sched() noexcept
70 : {
71 219 : return *static_cast<scheduler_type*>(this->sched_);
72 : }
73 :
74 : public:
75 : /** Construct with default concurrency.
76 :
77 : @throws std::system_error If the backend's infrastructure
78 : could not be created.
79 : */
80 224 : native_io_context() : io_context(Backend) {}
81 :
82 : /** Construct with a concurrency hint.
83 :
84 : @throws std::system_error If the backend's infrastructure
85 : could not be created.
86 :
87 : @param concurrency_hint Hint for the number of threads that
88 : call `run()`.
89 : */
90 2 : explicit native_io_context(unsigned concurrency_hint)
91 2 : : io_context(Backend, concurrency_hint)
92 : {
93 2 : }
94 :
95 : /** Construct with runtime tuning options.
96 :
97 : @throws std::invalid_argument If `opts.thread_pool_size` is
98 : less than 1 (POSIX), `opts.max_events_per_poll` is outside
99 : the range its member documents, or `opts.inline_budget_max`
100 : exceeds `INT_MAX` (platforms with a reactor backend).
101 :
102 : @throws std::system_error If the backend's infrastructure
103 : could not be created.
104 :
105 : @param opts Runtime options controlling scheduler and
106 : service behavior.
107 : @param concurrency_hint Hint for the number of threads that
108 : call `run()`.
109 : */
110 7 : explicit native_io_context(
111 : io_context_options const& opts,
112 : unsigned concurrency_hint = std::thread::hardware_concurrency())
113 7 : : io_context(Backend, opts, concurrency_hint)
114 : {
115 7 : }
116 :
117 : // Non-copyable, non-movable
118 : /// Copy construction is disabled; the context owns its services.
119 : native_io_context(native_io_context const&) = delete;
120 : /// Copy assignment is disabled; the context owns its services.
121 : native_io_context& operator=(native_io_context const&) = delete;
122 :
123 : /** Signal the context to stop processing.
124 :
125 : @throws std::system_error on Windows if the wakeup cannot be
126 : queued, which leaves blocked `run()` callers unable to wake
127 : until a later call succeeds.
128 : */
129 2 : void stop()
130 : {
131 2 : sched().stop();
132 2 : }
133 :
134 : /** Return whether the context stopped.
135 :
136 : @return `true` if the context has stopped.
137 : */
138 26 : bool stopped() const noexcept
139 : {
140 26 : return const_cast<native_io_context*>(this)->sched().stopped();
141 : }
142 :
143 : /// Restart the context after being stopped.
144 16 : void restart()
145 : {
146 16 : sched().restart();
147 16 : }
148 :
149 : /** Process all pending work items.
150 :
151 : @throws std::system_error if waiting on the operating system's
152 : event demultiplexer fails other than by interruption or
153 : another transient condition; the context can no longer
154 : dispatch work. On Windows, also if a wakeup needed to
155 : stop the context cannot be queued.
156 :
157 : @return The number of handlers executed.
158 : */
159 141 : std::size_t run()
160 : {
161 141 : frame_allocator_restore restore;
162 282 : return sched().run();
163 141 : }
164 :
165 : /** Process at most one pending work item.
166 :
167 : @throws std::system_error if waiting on the operating system's
168 : event demultiplexer fails other than by interruption or
169 : another transient condition; the context can no longer
170 : dispatch work. On Windows, also if a wakeup needed to
171 : stop the context cannot be queued.
172 :
173 : @return The number of handlers executed (0 or 1).
174 : */
175 2 : std::size_t run_one()
176 : {
177 2 : frame_allocator_restore restore;
178 4 : return sched().run_one();
179 2 : }
180 :
181 : /** Process work items for the specified duration.
182 :
183 : @throws std::system_error if waiting on the operating system's
184 : event demultiplexer fails other than by interruption or
185 : another transient condition; the context can no longer
186 : dispatch work. On Windows, also if a wakeup needed to
187 : stop the context cannot be queued.
188 :
189 : @param rel_time The duration for which to process work.
190 :
191 : @return The number of handlers executed.
192 : */
193 : template<class Rep, class Period>
194 6 : std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
195 : {
196 6 : return run_until(std::chrono::steady_clock::now() + rel_time);
197 : }
198 :
199 : /** Process work items until the specified time.
200 :
201 : @throws std::system_error if waiting on the operating system's
202 : event demultiplexer fails other than by interruption or
203 : another transient condition; the context can no longer
204 : dispatch work. On Windows, also if a wakeup needed to
205 : stop the context cannot be queued.
206 :
207 : @param abs_time The time point until which to process work.
208 :
209 : @return The number of handlers executed.
210 : */
211 : template<class Clock, class Duration>
212 : std::size_t
213 6 : run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
214 : {
215 6 : std::size_t n = 0;
216 10 : while (run_one_until(abs_time))
217 4 : if (n != (std::numeric_limits<std::size_t>::max)())
218 4 : ++n;
219 6 : return n;
220 : }
221 :
222 : /** Process at most one work item for the specified duration.
223 :
224 : @throws std::system_error if waiting on the operating system's
225 : event demultiplexer fails other than by interruption or
226 : another transient condition; the context can no longer
227 : dispatch work. On Windows, also if a wakeup needed to
228 : stop the context cannot be queued.
229 :
230 : @param rel_time The duration for which the call may block.
231 :
232 : @return The number of handlers executed (0 or 1).
233 : */
234 : template<class Rep, class Period>
235 : std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
236 : {
237 : return run_one_until(std::chrono::steady_clock::now() + rel_time);
238 : }
239 :
240 : /** Process at most one work item until the specified time.
241 :
242 : @throws std::system_error if waiting on the operating system's
243 : event demultiplexer fails other than by interruption or
244 : another transient condition; the context can no longer
245 : dispatch work. On Windows, also if a wakeup needed to
246 : stop the context cannot be queued.
247 :
248 : @param abs_time The time point until which the call may block.
249 :
250 : @return The number of handlers executed (0 or 1).
251 : */
252 : template<class Clock, class Duration>
253 : std::size_t
254 14 : run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
255 : {
256 14 : frame_allocator_restore restore;
257 14 : typename Clock::time_point now = Clock::now();
258 4 : for (;;)
259 : {
260 18 : auto rel_time = abs_time - now;
261 : using rel_type = decltype(rel_time);
262 18 : if (rel_time < rel_type::zero())
263 2 : rel_time = rel_type::zero();
264 16 : else if (rel_time > std::chrono::seconds(1))
265 8 : rel_time = std::chrono::seconds(1);
266 :
267 36 : std::size_t s = sched().wait_one(
268 : static_cast<long>(
269 18 : std::chrono::duration_cast<std::chrono::microseconds>(
270 : rel_time)
271 18 : .count()));
272 :
273 18 : if (s || stopped())
274 12 : return s;
275 :
276 6 : now = Clock::now();
277 6 : if (now >= abs_time)
278 2 : return 0;
279 : }
280 14 : }
281 :
282 : /** Process all ready work items without blocking.
283 :
284 : @throws std::system_error if waiting on the operating system's
285 : event demultiplexer fails other than by interruption or
286 : another transient condition; the context can no longer
287 : dispatch work. On Windows, also if a wakeup needed to
288 : stop the context cannot be queued.
289 :
290 : @return The number of handlers executed.
291 : */
292 12 : std::size_t poll()
293 : {
294 12 : frame_allocator_restore restore;
295 24 : return sched().poll();
296 12 : }
297 :
298 : /** Process at most one ready work item without blocking.
299 :
300 : @throws std::system_error if waiting on the operating system's
301 : event demultiplexer fails other than by interruption or
302 : another transient condition; the context can no longer
303 : dispatch work. On Windows, also if a wakeup needed to
304 : stop the context cannot be queued.
305 :
306 : @return The number of handlers executed (0 or 1).
307 : */
308 2 : std::size_t poll_one()
309 : {
310 2 : frame_allocator_restore restore;
311 4 : return sched().poll_one();
312 2 : }
313 : };
314 :
315 : } // namespace boost::corosio
316 :
317 : #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
|