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