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