include/boost/corosio/native/native_io_context.hpp

100.0% Lines (61 / 61) 65.8% Branches (50 / 76) 100.0% Functions (32 / 32)
native_io_context.hpp
f(x) Functions (32)
Function Calls Lines Branches Blocks
boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::~native_io_context() :64 232x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::~native_io_context() :64 232x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::sched() :69 109x 0.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::sched() :69 109x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::native_io_context() :80 224x 0.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::native_io_context() :80 224x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::native_io_context(unsigned int) :90 2x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::native_io_context(unsigned int) :90 2x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::native_io_context(boost::corosio::io_context_options const&, unsigned int) :110 6x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::native_io_context(boost::corosio::io_context_options const&, unsigned int) :110 6x 0.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::stop() :129 1x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::stop() :129 1x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::stopped() const :138 13x 0.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::stopped() const :138 13x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::restart() :144 8x 100.0% – 100.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::restart() :144 8x 0.0% – 100.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run() :159 70x 0.0% 0.0% 50.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::run() :159 70x 100.0% 50.0% 50.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run_one() :175 1x 100.0% – 50.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::run_one() :175 1x 100.0% 50.0% 50.0% unsigned long boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run_for<long long, std::__1::ratio<1l, 1000l>>(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000l>> const&) :194 2x 100.0% – 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run_for<long long, std::__1::ratio<1l, 1l>>(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1l>> const&) :194 1x 100.0% – 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::select_t{}>::run_for<long long, std::__1::ratio<1l, 1000l>>(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000l>> const&) :194 2x 100.0% – 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::select_t{}>::run_for<long long, std::__1::ratio<1l, 1l>>(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1l>> const&) :194 1x 100.0% – 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>>(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>> const&) :213 3x 0.0% 0.0% 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::select_t{}>::run_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>>(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>> const&) :213 3x 100.0% 75.0% 100.0% unsigned long boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::run_one_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>>(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>> const&) :254 7x 0.0% 0.0% 91.0% unsigned long boost::corosio::native_io_context<boost::corosio::select_t{}>::run_one_until<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>>(std::__1::chrono::time_point<std::__1::chrono::steady_clock, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>>> const&) :254 7x 100.0% 69.2% 90.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::poll() :292 6x 0.0% 0.0% 50.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::poll() :292 6x 100.0% 50.0% 50.0% boost::corosio::native_io_context<boost::corosio::kqueue_t{}>::poll_one() :308 1x 100.0% – 50.0% boost::corosio::native_io_context<boost::corosio::select_t{}>::poll_one() :308 1x 100.0% 50.0% 50.0%
Line Branch TLA Hits 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 218x scheduler_type& sched() noexcept
70 {
71 218x 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 448x 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 4x explicit native_io_context(unsigned concurrency_hint)
91 2x : io_context(Backend, concurrency_hint)
92 2x {
93 4x }
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 12x explicit native_io_context(
111 io_context_options const& opts,
112 unsigned concurrency_hint = std::thread::hardware_concurrency())
113 6x : io_context(Backend, opts, concurrency_hint)
114 6x {
115 12x }
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 2x void stop()
130 {
131 2x sched().stop();
132 2x }
133
134 /** Return whether the context stopped.
135
136 @return `true` if the context has stopped.
137 */
138 26x bool stopped() const noexcept
139 {
140 26x return const_cast<native_io_context*>(this)->sched().stopped();
141 }
142
143 /// Restart the context after being stopped.
144 16x void restart()
145 {
146 16x sched().restart();
147 16x }
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 140x std::size_t run()
160 {
161 140x frame_allocator_restore restore;
162
2/4
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
140x return sched().run();
163 140x }
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 2x std::size_t run_one()
176 {
177 2x frame_allocator_restore restore;
178
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2x return sched().run_one();
179 2x }
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 6x std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
195 {
196 6x 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 6x run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
214 {
215 6x std::size_t n = 0;
216
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
10x while (run_one_until(abs_time))
217
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
4x if (n != (std::numeric_limits<std::size_t>::max)())
218 4x ++n;
219 6x 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 14x run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
255 {
256 14x frame_allocator_restore restore;
257 14x typename Clock::time_point now = Clock::now();
258 18x for (;;)
259 {
260
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18x auto rel_time = abs_time - now;
261 using rel_type = decltype(rel_time);
262
5/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 1 time.
18x if (rel_time < rel_type::zero())
263 2x rel_time = rel_type::zero();
264
8/12
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 4 times.
16x else if (rel_time > std::chrono::seconds(1))
265
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8x rel_time = std::chrono::seconds(1);
266
267
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18x std::size_t s = sched().wait_one(
268 static_cast<long>(
269
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18x std::chrono::duration_cast<std::chrono::microseconds>(
270 rel_time)
271 18x .count()));
272
273
8/8
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 3 times.
18x if (s || stopped())
274 12x return s;
275
276 6x now = Clock::now();
277
5/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 2 times.
6x if (now >= abs_time)
278 2x return 0;
279 }
280 14x }
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 12x std::size_t poll()
293 {
294 12x frame_allocator_restore restore;
295
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12x return sched().poll();
296 12x }
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 2x std::size_t poll_one()
309 {
310 2x frame_allocator_restore restore;
311
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2x return sched().poll_one();
312 2x }
313 };
314
315 } // namespace boost::corosio
316
317 #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
318