TLA Line data 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 io_context, epoll_t, 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 HIT 179 : scheduler_type& sched() noexcept
70 : {
71 179 : return *static_cast<scheduler_type*>(this->sched_);
72 : }
73 :
74 : public:
75 : /** Construct with default concurrency. */
76 188 : native_io_context() : io_context(Backend) {}
77 :
78 : /** Construct with a concurrency hint.
79 :
80 : @param concurrency_hint Hint for the number of threads that
81 : call `run()`.
82 : */
83 2 : explicit native_io_context(unsigned concurrency_hint)
84 2 : : io_context(Backend, concurrency_hint)
85 : {
86 2 : }
87 :
88 : /** Construct with runtime tuning options.
89 :
90 : @param opts Runtime options controlling scheduler and
91 : service behavior.
92 : @param concurrency_hint Hint for the number of threads that
93 : call `run()`.
94 : */
95 7 : explicit native_io_context(
96 : io_context_options const& opts,
97 : unsigned concurrency_hint = std::thread::hardware_concurrency())
98 7 : : io_context(Backend, opts, concurrency_hint)
99 : {
100 7 : }
101 :
102 : // Non-copyable, non-movable
103 : /// Copy construction is disabled; the context owns its services.
104 : native_io_context(native_io_context const&) = delete;
105 : /// Copy assignment is disabled; the context owns its services.
106 : native_io_context& operator=(native_io_context const&) = delete;
107 :
108 : /// Signal the context to stop processing.
109 2 : void stop()
110 : {
111 2 : sched().stop();
112 2 : }
113 :
114 : /** Return whether the context stopped.
115 :
116 : @return `true` if the context has stopped.
117 : */
118 22 : bool stopped() const noexcept
119 : {
120 22 : return const_cast<native_io_context*>(this)->sched().stopped();
121 : }
122 :
123 : /// Restart the context after being stopped.
124 16 : void restart()
125 : {
126 16 : sched().restart();
127 16 : }
128 :
129 : /** Process all pending work items.
130 :
131 : @return The number of handlers executed.
132 : */
133 125 : std::size_t run()
134 : {
135 125 : return sched().run();
136 : }
137 :
138 : /** Process at most one pending work item.
139 :
140 : @return The number of handlers executed (0 or 1).
141 : */
142 : std::size_t run_one()
143 : {
144 : return sched().run_one();
145 : }
146 :
147 : /** Process work items for the specified duration.
148 :
149 : @param rel_time The duration for which to process work.
150 :
151 : @return The number of handlers executed.
152 : */
153 : template<class Rep, class Period>
154 4 : std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
155 : {
156 4 : return run_until(std::chrono::steady_clock::now() + rel_time);
157 : }
158 :
159 : /** Process work items until the specified time.
160 :
161 : @param abs_time The time point until which to process work.
162 :
163 : @return The number of handlers executed.
164 : */
165 : template<class Clock, class Duration>
166 : std::size_t
167 4 : run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
168 : {
169 4 : std::size_t n = 0;
170 6 : while (run_one_until(abs_time))
171 2 : if (n != (std::numeric_limits<std::size_t>::max)())
172 2 : ++n;
173 4 : return n;
174 : }
175 :
176 : /** Process at most one work item for the specified duration.
177 :
178 : @param rel_time The duration for which the call may block.
179 :
180 : @return The number of handlers executed (0 or 1).
181 : */
182 : template<class Rep, class Period>
183 : std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
184 : {
185 : return run_one_until(std::chrono::steady_clock::now() + rel_time);
186 : }
187 :
188 : /** Process at most one work item until the specified time.
189 :
190 : @param abs_time The time point until which the call may block.
191 :
192 : @return The number of handlers executed (0 or 1).
193 : */
194 : template<class Clock, class Duration>
195 : std::size_t
196 10 : run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
197 : {
198 10 : typename Clock::time_point now = Clock::now();
199 2 : for (;;)
200 : {
201 12 : auto rel_time = abs_time - now;
202 : using rel_type = decltype(rel_time);
203 12 : if (rel_time < rel_type::zero())
204 2 : rel_time = rel_type::zero();
205 10 : else if (rel_time > std::chrono::seconds(1))
206 2 : rel_time = std::chrono::seconds(1);
207 :
208 24 : std::size_t s = sched().wait_one(
209 : static_cast<long>(
210 12 : std::chrono::duration_cast<std::chrono::microseconds>(
211 : rel_time)
212 12 : .count()));
213 :
214 12 : if (s || stopped())
215 10 : return s;
216 :
217 4 : now = Clock::now();
218 4 : if (now >= abs_time)
219 2 : return 0;
220 : }
221 : }
222 :
223 : /** Process all ready work items without blocking.
224 :
225 : @return The number of handlers executed.
226 : */
227 2 : std::size_t poll()
228 : {
229 2 : return sched().poll();
230 : }
231 :
232 : /** Process at most one ready work item without blocking.
233 :
234 : @return The number of handlers executed (0 or 1).
235 : */
236 : std::size_t poll_one()
237 : {
238 : return sched().poll_one();
239 : }
240 : };
241 :
242 : } // namespace boost::corosio
243 :
244 : #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
|