include/boost/corosio/native/native_io_context.hpp

92.3% Lines (36/39) 100.0% Functions (22/22) 66.7% Branches (16/24)
include/boost/corosio/native/native_io_context.hpp
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Steve Gerbino
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
11 #define BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
12
13 #include <boost/corosio/io_context.hpp>
14 #include <boost/corosio/backend.hpp>
15
16 #if BOOST_COROSIO_HAS_EPOLL
17 #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
18 #endif
19
20 #if BOOST_COROSIO_HAS_SELECT
21 #include <boost/corosio/native/detail/select/select_scheduler.hpp>
22 #endif
23
24 #if BOOST_COROSIO_HAS_KQUEUE
25 #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp>
26 #endif
27
28 #if BOOST_COROSIO_HAS_IOCP
29 #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
30 #endif
31
32 namespace boost::corosio {
33
34 /** An I/O context with devirtualized event loop methods.
35
36 This class template inherits from @ref io_context and shadows
37 all public methods with versions that call the concrete
38 scheduler directly, bypassing virtual dispatch. No new state
39 is added.
40
41 A `native_io_context` IS-A `io_context` and can be passed
42 anywhere an `io_context&` is accepted, in which case virtual
43 dispatch is used transparently.
44
45 @tparam Backend A backend tag value (e.g., `epoll`,
46 `iocp`) whose type provides `scheduler_type`.
47
48 @par Thread Safety
49 Same as the underlying context type.
50
51 @par Example
52 @code
53 #include <boost/corosio/native/native_io_context.hpp>
54
55 native_io_context<epoll> ctx;
56 ctx.poll(); // devirtualized call
57 @endcode
58
59 @see io_context, epoll_t, iocp_t
60 */
61 template<auto Backend>
62 class native_io_context : public io_context
63 {
64 using backend_type = decltype(Backend);
65 using scheduler_type = typename backend_type::scheduler_type;
66
67 18 scheduler_type& sched() noexcept
68 {
69 18 return *static_cast<scheduler_type*>(this->sched_);
70 }
71
72 public:
73 /** Construct with default concurrency. */
74 20 native_io_context() : io_context(Backend) {}
75
76 /** Construct with a concurrency hint.
77
78 @param concurrency_hint Hint for the number of threads that
79 will call `run()`.
80 */
81 4 explicit native_io_context(unsigned concurrency_hint)
82 2 : io_context(Backend, concurrency_hint)
83 2 {
84 4 }
85
86 // Non-copyable, non-movable
87 native_io_context(native_io_context const&) = delete;
88 native_io_context& operator=(native_io_context const&) = delete;
89
90 /// Signal the context to stop processing.
91 2 void stop()
92 {
93 2 sched().stop();
94 2 }
95
96 /// Return whether the context has been stopped.
97 8 bool stopped() const noexcept
98 {
99 8 return const_cast<native_io_context*>(this)->sched().stopped();
100 }
101
102 /// Restart the context after being stopped.
103 2 void restart()
104 {
105 2 sched().restart();
106 2 }
107
108 /** Process all pending work items.
109
110 @return The number of handlers executed.
111 */
112 std::size_t run()
113 {
114 return sched().run();
115 }
116
117 /** Process at most one pending work item.
118
119 @return The number of handlers executed (0 or 1).
120 */
121 std::size_t run_one()
122 {
123 return sched().run_one();
124 }
125
126 /** Process work items for the specified duration.
127
128 @param rel_time The duration for which to process work.
129
130 @return The number of handlers executed.
131 */
132 template<class Rep, class Period>
133 2 std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
134 {
135 2 return run_until(std::chrono::steady_clock::now() + rel_time);
136 }
137
138 /** Process work items until the specified time.
139
140 @param abs_time The time point until which to process work.
141
142 @return The number of handlers executed.
143 */
144 template<class Clock, class Duration>
145 std::size_t
146 2 run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
147 {
148 2 std::size_t n = 0;
149
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
4 while (run_one_until(abs_time))
150
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
2 if (n != (std::numeric_limits<std::size_t>::max)())
151 2 ++n;
152 2 return n;
153 }
154
155 /** Process at most one work item for the specified duration.
156
157 @param rel_time The duration for which the call may block.
158
159 @return The number of handlers executed (0 or 1).
160 */
161 template<class Rep, class Period>
162 std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
163 {
164 return run_one_until(std::chrono::steady_clock::now() + rel_time);
165 }
166
167 /** Process at most one work item until the specified time.
168
169 @param abs_time The time point until which the call may block.
170
171 @return The number of handlers executed (0 or 1).
172 */
173 template<class Clock, class Duration>
174 std::size_t
175 4 run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
176 {
177 4 typename Clock::time_point now = Clock::now();
178
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 while (now < abs_time)
179 {
180 4 auto rel_time = abs_time - now;
181
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (rel_time > std::chrono::seconds(1))
182 rel_time = std::chrono::seconds(1);
183
184 8 std::size_t s = sched().wait_one(
185 static_cast<long>(
186 4 std::chrono::duration_cast<std::chrono::microseconds>(
187 rel_time)
188 4 .count()));
189
190
6/8
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
4 if (s || stopped())
191 4 return s;
192
193 now = Clock::now();
194 }
195 return 0;
196 4 }
197
198 /** Process all ready work items without blocking.
199
200 @return The number of handlers executed.
201 */
202 2 std::size_t poll()
203 {
204 2 return sched().poll();
205 }
206
207 /** Process at most one ready work item without blocking.
208
209 @return The number of handlers executed (0 or 1).
210 */
211 std::size_t poll_one()
212 {
213 return sched().poll_one();
214 }
215 };
216
217 } // namespace boost::corosio
218
219 #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
220