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