src/corosio/src/io_context.cpp

48.8% Lines (20/41) 50.0% List of functions (5/10) 40.0% Branches (2/5)
io_context.cpp
f(x) Functions (10)
Line Branch 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 epoll_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
53 {
54 auto& sched = ctx.make_service<detail::epoll_scheduler>(
55 static_cast<int>(concurrency_hint));
56
57 auto& tcp_svc = ctx.make_service<detail::epoll_tcp_service>();
58 ctx.make_service<detail::epoll_tcp_acceptor_service>(tcp_svc);
59 ctx.make_service<detail::epoll_udp_service>();
60
61 return sched;
62 }
63 #endif
64
65 #if BOOST_COROSIO_HAS_SELECT
66 detail::scheduler&
67 select_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
68 {
69 auto& sched = ctx.make_service<detail::select_scheduler>(
70 static_cast<int>(concurrency_hint));
71
72 auto& tcp_svc = ctx.make_service<detail::select_tcp_service>();
73 ctx.make_service<detail::select_tcp_acceptor_service>(tcp_svc);
74 ctx.make_service<detail::select_udp_service>();
75
76 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 auto& tcp_svc = ctx.make_service<detail::kqueue_tcp_service>();
88 ctx.make_service<detail::kqueue_tcp_acceptor_service>(tcp_svc);
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 431x iocp_t::construct(capy::execution_context& ctx, unsigned concurrency_hint)
98 {
99 862x auto& sched = ctx.make_service<detail::win_scheduler>(
100
1/1
✓ Branch 2 → 3 taken 431 times.
431x static_cast<int>(concurrency_hint));
101
102 431x auto& tcp_svc = ctx.make_service<detail::win_tcp_service>();
103 431x ctx.make_service<detail::win_tcp_acceptor_service>(tcp_svc);
104 431x ctx.make_service<detail::win_udp_service>();
105 431x ctx.make_service<detail::win_signals>();
106 431x ctx.make_service<detail::win_file_service>();
107 431x ctx.make_service<detail::win_random_access_file_service>();
108
109 431x 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&>(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 auto& iocp_sched = static_cast<detail::win_scheduler&>(sched);
157 iocp_sched.configure_iocp(opts.gqcs_timeout_ms);
158 if (opts.single_threaded)
159 iocp_sched.configure_single_threaded(true);
160 #endif
161
162 (void)sched;
163 (void)opts;
164 }
165
166 detail::scheduler&
167 195x construct_default(capy::execution_context& ctx, unsigned concurrency_hint)
168 {
169 #if BOOST_COROSIO_HAS_IOCP
170 195x return iocp_t::construct(ctx, concurrency_hint);
171 #elif BOOST_COROSIO_HAS_EPOLL
172 return epoll_t::construct(ctx, concurrency_hint);
173 #elif BOOST_COROSIO_HAS_KQUEUE
174 return kqueue_t::construct(ctx, concurrency_hint);
175 #elif BOOST_COROSIO_HAS_SELECT
176 return select_t::construct(ctx, concurrency_hint);
177 #endif
178 }
179
180 } // anonymous namespace
181
182 194x io_context::io_context() : io_context(std::thread::hardware_concurrency()) {}
183
184 195x io_context::io_context(unsigned concurrency_hint)
185 : capy::execution_context(this)
186
1/1
✓ Branch 3 → 4 taken 195 times.
195x , sched_(&construct_default(*this, concurrency_hint))
187 {
188 195x }
189
190 io_context::io_context(
191 io_context_options const& opts,
192 unsigned concurrency_hint)
193 : capy::execution_context(this)
194 , sched_(nullptr)
195 {
196 pre_create_services(*this, opts);
197 sched_ = &construct_default(*this, concurrency_hint);
198 apply_scheduler_options(*sched_, opts);
199 }
200
201 void
202 io_context::apply_options_pre_(io_context_options const& opts)
203 {
204 pre_create_services(*this, opts);
205 }
206
207 void
208 io_context::apply_options_post_(io_context_options const& opts)
209 {
210 apply_scheduler_options(*sched_, opts);
211 }
212
213 431x io_context::~io_context()
214 {
215 431x shutdown();
216 431x destroy();
217 431x }
218
219 } // namespace boost::corosio
220