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 199 : scheduler_type& sched() noexcept
70 : {
71 199 : return *static_cast<scheduler_type*>(this->sched_);
72 : }
73 :
74 : public:
75 : /** Construct with default concurrency. */
76 200 : 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 26 : bool stopped() const noexcept
119 : {
120 26 : 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 129 : std::size_t run()
134 : {
135 129 : frame_allocator_restore restore;
136 258 : return sched().run();
137 129 : }
138 :
139 : /** Process at most one pending work item.
140 :
141 : @return The number of handlers executed (0 or 1).
142 : */
143 2 : std::size_t run_one()
144 : {
145 2 : frame_allocator_restore restore;
146 4 : return sched().run_one();
147 2 : }
148 :
149 : /** Process work items for the specified duration.
150 :
151 : @param rel_time The duration for which to process work.
152 :
153 : @return The number of handlers executed.
154 : */
155 : template<class Rep, class Period>
156 6 : std::size_t run_for(std::chrono::duration<Rep, Period> const& rel_time)
157 : {
158 6 : return run_until(std::chrono::steady_clock::now() + rel_time);
159 : }
160 :
161 : /** Process work items until the specified time.
162 :
163 : @param abs_time The time point until which to process work.
164 :
165 : @return The number of handlers executed.
166 : */
167 : template<class Clock, class Duration>
168 : std::size_t
169 6 : run_until(std::chrono::time_point<Clock, Duration> const& abs_time)
170 : {
171 6 : std::size_t n = 0;
172 10 : while (run_one_until(abs_time))
173 4 : if (n != (std::numeric_limits<std::size_t>::max)())
174 4 : ++n;
175 6 : return n;
176 : }
177 :
178 : /** Process at most one work item for the specified duration.
179 :
180 : @param rel_time The duration for which the call may block.
181 :
182 : @return The number of handlers executed (0 or 1).
183 : */
184 : template<class Rep, class Period>
185 : std::size_t run_one_for(std::chrono::duration<Rep, Period> const& rel_time)
186 : {
187 : return run_one_until(std::chrono::steady_clock::now() + rel_time);
188 : }
189 :
190 : /** Process at most one work item until the specified time.
191 :
192 : @param abs_time The time point until which the call may block.
193 :
194 : @return The number of handlers executed (0 or 1).
195 : */
196 : template<class Clock, class Duration>
197 : std::size_t
198 14 : run_one_until(std::chrono::time_point<Clock, Duration> const& abs_time)
199 : {
200 14 : frame_allocator_restore restore;
201 14 : typename Clock::time_point now = Clock::now();
202 4 : for (;;)
203 : {
204 18 : auto rel_time = abs_time - now;
205 : using rel_type = decltype(rel_time);
206 18 : if (rel_time < rel_type::zero())
207 2 : rel_time = rel_type::zero();
208 16 : else if (rel_time > std::chrono::seconds(1))
209 8 : rel_time = std::chrono::seconds(1);
210 :
211 36 : std::size_t s = sched().wait_one(
212 : static_cast<long>(
213 18 : std::chrono::duration_cast<std::chrono::microseconds>(
214 : rel_time)
215 18 : .count()));
216 :
217 18 : if (s || stopped())
218 12 : return s;
219 :
220 6 : now = Clock::now();
221 6 : if (now >= abs_time)
222 2 : return 0;
223 : }
224 14 : }
225 :
226 : /** Process all ready work items without blocking.
227 :
228 : @return The number of handlers executed.
229 : */
230 4 : std::size_t poll()
231 : {
232 4 : frame_allocator_restore restore;
233 8 : return sched().poll();
234 4 : }
235 :
236 : /** Process at most one ready work item without blocking.
237 :
238 : @return The number of handlers executed (0 or 1).
239 : */
240 2 : std::size_t poll_one()
241 : {
242 2 : frame_allocator_restore restore;
243 4 : return sched().poll_one();
244 2 : }
245 : };
246 :
247 : } // namespace boost::corosio
248 :
249 : #endif // BOOST_COROSIO_NATIVE_NATIVE_IO_CONTEXT_HPP
|