include/boost/corosio/native/native_io_context.hpp
100.0% Lines (61 / 61)
65.8% Branches (50 / 76)
100.0% Functions (32 / 32)
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 |