src/corosio/src/io_context.cpp

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