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