src/corosio/src/io_context.cpp

50.8% Lines (30/59) 54.5% List of functions (6/11)
io_context.cpp
f(x) Functions (11)
Line 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 #include <boost/corosio/io_context.hpp>
12 #include <boost/corosio/backend.hpp>
13 #include <boost/corosio/detail/thread_pool.hpp>
14
15 #include <stdexcept>
16 #include <thread>
17
18 #if BOOST_COROSIO_HAS_EPOLL
19 #include <boost/corosio/native/detail/epoll/epoll_scheduler.hpp>
20 #include <boost/corosio/native/detail/epoll/epoll_tcp_service.hpp>
21 #include <boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp>
22 #include <boost/corosio/native/detail/epoll/epoll_udp_service.hpp>
23 #include <boost/corosio/native/detail/epoll/epoll_local_stream_service.hpp>
24 #include <boost/corosio/native/detail/epoll/epoll_local_stream_acceptor_service.hpp>
25 #include <boost/corosio/native/detail/epoll/epoll_local_datagram_service.hpp>
26 #endif
27
28 #if BOOST_COROSIO_HAS_SELECT
29 #include <boost/corosio/native/detail/select/select_scheduler.hpp>
30 #include <boost/corosio/native/detail/select/select_tcp_service.hpp>
31 #include <boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp>
32 #include <boost/corosio/native/detail/select/select_udp_service.hpp>
33 #include <boost/corosio/native/detail/select/select_local_stream_service.hpp>
34 #include <boost/corosio/native/detail/select/select_local_stream_acceptor_service.hpp>
35 #include <boost/corosio/native/detail/select/select_local_datagram_service.hpp>
36 #endif
37
38 #if BOOST_COROSIO_HAS_KQUEUE
39 #include <boost/corosio/native/detail/kqueue/kqueue_scheduler.hpp>
40 #include <boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp>
41 #include <boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp>
42 #include <boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp>
43 #include <boost/corosio/native/detail/kqueue/kqueue_local_stream_service.hpp>
44 #include <boost/corosio/native/detail/kqueue/kqueue_local_stream_acceptor_service.hpp>
45 #include <boost/corosio/native/detail/kqueue/kqueue_local_datagram_service.hpp>
46 #endif
47
48 #if BOOST_COROSIO_HAS_IOCP
49 #include <boost/corosio/native/detail/iocp/win_scheduler.hpp>
50 #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
51 #include <boost/corosio/native/detail/iocp/win_udp_service.hpp>
52 #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp>
53 #include <boost/corosio/native/detail/iocp/win_local_dgram_service.hpp>
54 #include <boost/corosio/native/detail/iocp/win_signals.hpp>
55 #include <boost/corosio/native/detail/iocp/win_file_service.hpp>
56 #include <boost/corosio/native/detail/iocp/win_random_access_file_service.hpp>
57 #endif
58
59 namespace boost::corosio {
60
61 #if BOOST_COROSIO_HAS_EPOLL
62 detail::scheduler&
63 355x epoll_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
64 {
65 710x auto& sched = ctx.make_service<detail::epoll_scheduler>(
66 355x static_cast<int>(concurrency_hint));
67
68 355x ctx.make_service<detail::epoll_tcp_service>();
69 355x ctx.make_service<detail::epoll_tcp_acceptor_service>();
70 355x ctx.make_service<detail::epoll_udp_service>();
71 355x ctx.make_service<detail::epoll_local_stream_service>();
72 355x ctx.make_service<detail::epoll_local_stream_acceptor_service>();
73 355x ctx.make_service<detail::epoll_local_datagram_service>();
74
75 355x return sched;
76 }
77 #endif
78
79 #if BOOST_COROSIO_HAS_SELECT
80 detail::scheduler&
81 228x select_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
82 {
83 456x auto& sched = ctx.make_service<detail::select_scheduler>(
84 228x static_cast<int>(concurrency_hint));
85
86 228x ctx.make_service<detail::select_tcp_service>();
87 228x ctx.make_service<detail::select_tcp_acceptor_service>();
88 228x ctx.make_service<detail::select_udp_service>();
89 228x ctx.make_service<detail::select_local_stream_service>();
90 228x ctx.make_service<detail::select_local_stream_acceptor_service>();
91 228x ctx.make_service<detail::select_local_datagram_service>();
92
93 228x return sched;
94 }
95 #endif
96
97 #if BOOST_COROSIO_HAS_KQUEUE
98 detail::scheduler&
99 kqueue_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
100 {
101 auto& sched = ctx.make_service<detail::kqueue_scheduler>(
102 static_cast<int>(concurrency_hint));
103
104 ctx.make_service<detail::kqueue_tcp_service>();
105 ctx.make_service<detail::kqueue_tcp_acceptor_service>();
106 ctx.make_service<detail::kqueue_udp_service>();
107 ctx.make_service<detail::kqueue_local_stream_service>();
108 ctx.make_service<detail::kqueue_local_stream_acceptor_service>();
109 ctx.make_service<detail::kqueue_local_datagram_service>();
110
111 return sched;
112 }
113 #endif
114
115 #if BOOST_COROSIO_HAS_IOCP
116 detail::scheduler&
117 iocp_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
118 {
119 auto& sched = ctx.make_service<detail::win_scheduler>(
120 static_cast<int>(concurrency_hint));
121
122 auto& tcp_svc = ctx.make_service<detail::win_tcp_service>();
123 ctx.make_service<detail::win_tcp_acceptor_service>(tcp_svc);
124 ctx.make_service<detail::win_udp_service>();
125 auto& local_svc =
126 ctx.make_service<detail::win_local_stream_service>(tcp_svc);
127 ctx.make_service<detail::win_local_stream_acceptor_service>(local_svc);
128 ctx.make_service<detail::win_local_dgram_service>();
129 ctx.make_service<detail::win_signals>();
130 ctx.make_service<detail::win_file_service>();
131 ctx.make_service<detail::win_random_access_file_service>();
132
133 return sched;
134 }
135 #endif
136
137 namespace {
138
139 // Pre-create services that must exist before construct() runs.
140 void
141 pre_create_services(
142 capy::execution_context& ctx,
143 io_context_options const& opts)
144 {
145 #if BOOST_COROSIO_POSIX
146 if (opts.thread_pool_size < 1)
147 throw std::invalid_argument(
148 "thread_pool_size must be at least 1");
149 // Pre-create the shared thread pool with the configured size.
150 // This must happen before construct() because the scheduler
151 // constructor creates file and resolver services that call
152 // get_or_create_pool(), which would create a 1-thread pool.
153 if (opts.thread_pool_size != 1)
154 ctx.make_service<detail::thread_pool>(opts.thread_pool_size);
155 #endif
156
157 (void)ctx;
158 (void)opts;
159 }
160
161 // Apply runtime tuning to the scheduler after construction.
162 void
163 apply_scheduler_options(
164 detail::scheduler& sched,
165 io_context_options const& opts)
166 {
167 #if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_KQUEUE || BOOST_COROSIO_HAS_SELECT
168 auto& reactor =
169 static_cast<detail::reactor_scheduler&>(sched);
170 reactor.configure_reactor(
171 opts.max_events_per_poll,
172 opts.inline_budget_initial,
173 opts.inline_budget_max,
174 opts.unassisted_budget);
175 if (opts.single_threaded)
176 reactor.configure_single_threaded(true);
177 #endif
178
179 #if BOOST_COROSIO_HAS_IOCP
180 auto& iocp_sched = static_cast<detail::win_scheduler&>(sched);
181 iocp_sched.configure_iocp(opts.gqcs_timeout_ms);
182 if (opts.single_threaded)
183 iocp_sched.configure_single_threaded(true);
184 #endif
185
186 (void)sched;
187 (void)opts;
188 }
189
190 detail::scheduler&
191 127x construct_default(capy::execution_context& ctx, unsigned concurrency_hint)
192 {
193 #if BOOST_COROSIO_HAS_IOCP
194 return iocp_t::construct(ctx, concurrency_hint);
195 #elif BOOST_COROSIO_HAS_EPOLL
196 127x return epoll_t::construct(ctx, concurrency_hint);
197 #elif BOOST_COROSIO_HAS_KQUEUE
198 return kqueue_t::construct(ctx, concurrency_hint);
199 #elif BOOST_COROSIO_HAS_SELECT
200 return select_t::construct(ctx, concurrency_hint);
201 #endif
202 }
203
204 } // anonymous namespace
205
206 126x io_context::io_context() : io_context(std::thread::hardware_concurrency()) {}
207
208 127x io_context::io_context(unsigned concurrency_hint)
209 : capy::execution_context(this)
210 127x , sched_(&construct_default(*this, concurrency_hint))
211 {
212 127x }
213
214 io_context::io_context(
215 io_context_options const& opts,
216 unsigned concurrency_hint)
217 : capy::execution_context(this)
218 , sched_(nullptr)
219 {
220 pre_create_services(*this, opts);
221 sched_ = &construct_default(*this, concurrency_hint);
222 apply_scheduler_options(*sched_, opts);
223 }
224
225 void
226 io_context::apply_options_pre_(io_context_options const& opts)
227 {
228 pre_create_services(*this, opts);
229 }
230
231 void
232 io_context::apply_options_post_(io_context_options const& opts)
233 {
234 apply_scheduler_options(*sched_, opts);
235 }
236
237 583x io_context::~io_context()
238 {
239 583x shutdown();
240 583x destroy();
241 583x }
242
243 } // namespace boost::corosio
244