TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/corosio
8 : //
9 :
10 : #ifndef BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
11 : #define BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
12 :
13 : #include <boost/corosio/local_stream_acceptor.hpp>
14 : #include <boost/corosio/native/native_local_stream_socket.hpp>
15 : #include <boost/corosio/backend.hpp>
16 : #include <boost/corosio/detail/op_base.hpp>
17 :
18 : #ifndef BOOST_COROSIO_MRDOCS
19 : #if BOOST_COROSIO_HAS_EPOLL
20 : #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
21 : #endif
22 :
23 : #if BOOST_COROSIO_HAS_SELECT
24 : #include <boost/corosio/native/detail/select/select_types.hpp>
25 : #endif
26 :
27 : #if BOOST_COROSIO_HAS_KQUEUE
28 : #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
29 : #endif
30 :
31 : #if BOOST_COROSIO_HAS_URING
32 : #include <boost/corosio/native/detail/uring/uring_types.hpp>
33 : #endif
34 :
35 : #if BOOST_COROSIO_HAS_IOCP
36 : #include <boost/corosio/native/detail/iocp/win_local_stream_acceptor_service.hpp>
37 : #endif
38 : #endif // !BOOST_COROSIO_MRDOCS
39 :
40 : namespace boost::corosio {
41 :
42 : /** An asynchronous Unix stream acceptor with devirtualized accept.
43 :
44 : This class template inherits from @ref local_stream_acceptor
45 : and shadows both `accept` overloads (the peer-reference form
46 : and the move-return form) with versions that call the backend
47 : implementation directly, allowing the compiler to inline
48 : through the entire call chain. The move-return form yields a
49 : @ref native_local_stream_socket so subsequent I/O on the peer
50 : is also devirtualized.
51 :
52 : Non-async operations (`listen`, `close`, `cancel`) remain
53 : unchanged and dispatch through the compiled library.
54 :
55 : A `native_local_stream_acceptor` IS-A `local_stream_acceptor`
56 : and can be passed to any function expecting
57 : `local_stream_acceptor&`.
58 :
59 : @tparam Backend A backend tag value (e.g., `epoll`).
60 :
61 : @par Thread Safety
62 : Same as @ref local_stream_acceptor.
63 :
64 : @see local_stream_acceptor, epoll_t, iocp_t
65 : */
66 : template<auto Backend>
67 : class native_local_stream_acceptor : public local_stream_acceptor
68 : {
69 : using backend_type = decltype(Backend);
70 : using impl_type = typename backend_type::local_stream_acceptor_type;
71 : using service_type =
72 : typename backend_type::local_stream_acceptor_service_type;
73 :
74 HIT 10 : impl_type& get_impl() noexcept
75 : {
76 10 : return *static_cast<impl_type*>(h_.get());
77 : }
78 :
79 : struct native_wait_awaitable : detail::void_op_base<native_wait_awaitable>
80 : {
81 : native_local_stream_acceptor& acc_;
82 : wait_type w_;
83 :
84 6 : native_wait_awaitable(
85 : native_local_stream_acceptor& acc, wait_type w) noexcept
86 6 : : acc_(acc)
87 6 : , w_(w)
88 : {
89 6 : }
90 :
91 : std::coroutine_handle<>
92 4 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
93 : {
94 4 : return acc_.get_impl().wait(h, ex, w_, this->token_, &this->ec_);
95 : }
96 : };
97 :
98 : struct native_accept_awaitable
99 : : detail::void_op_base<native_accept_awaitable>
100 : {
101 : native_local_stream_acceptor& acc_;
102 : local_stream_socket& peer_;
103 : mutable io_object::implementation* peer_impl_ = nullptr;
104 :
105 8 : native_accept_awaitable(
106 : native_local_stream_acceptor& acc,
107 : local_stream_socket& peer) noexcept
108 8 : : acc_(acc)
109 8 : , peer_(peer)
110 : {
111 8 : }
112 :
113 8 : [[nodiscard]] capy::io_result<> await_resume() const noexcept
114 : {
115 8 : if (!this->ec_)
116 4 : acc_.reset_peer_impl(peer_, peer_impl_);
117 8 : return {this->ec_};
118 : }
119 :
120 : std::coroutine_handle<>
121 4 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
122 : {
123 12 : return acc_.get_impl().accept(
124 12 : h, ex, this->token_, &this->ec_, &peer_impl_);
125 : }
126 : };
127 :
128 : struct native_move_accept_awaitable
129 : : detail::void_op_base<native_move_accept_awaitable>
130 : {
131 : native_local_stream_acceptor& acc_;
132 : mutable io_object::implementation* peer_impl_ = nullptr;
133 :
134 6 : explicit native_move_accept_awaitable(
135 : native_local_stream_acceptor& acc) noexcept
136 6 : : acc_(acc)
137 : {
138 6 : }
139 :
140 : [[nodiscard]] capy::io_result<native_local_stream_socket<Backend>>
141 6 : await_resume() const noexcept
142 : {
143 6 : if (this->ec_ || !peer_impl_)
144 : return {
145 4 : this->ec_,
146 4 : native_local_stream_socket<Backend>(acc_.context())};
147 :
148 2 : native_local_stream_socket<Backend> peer(acc_.context());
149 2 : acc_.reset_peer_impl(peer, peer_impl_);
150 2 : return {this->ec_, std::move(peer)};
151 2 : }
152 :
153 : std::coroutine_handle<>
154 2 : dispatch(std::coroutine_handle<> h, capy::executor_ref ex) const
155 : {
156 6 : return acc_.get_impl().accept(
157 6 : h, ex, this->token_, &this->ec_, &peer_impl_);
158 : }
159 : };
160 :
161 : public:
162 : /** Construct a native acceptor from an execution context.
163 :
164 : @param ctx The execution context that will own this acceptor.
165 : */
166 18 : explicit native_local_stream_acceptor(capy::execution_context& ctx)
167 18 : : local_stream_acceptor(create_handle<service_type>(ctx), ctx)
168 : {
169 18 : }
170 :
171 : /** Construct a native acceptor from an executor.
172 :
173 : @param ex The executor whose context will own the acceptor.
174 : */
175 : template<class Ex>
176 : requires(!std::same_as<
177 : std::remove_cvref_t<Ex>,
178 : native_local_stream_acceptor>) &&
179 : capy::Executor<Ex>
180 : explicit native_local_stream_acceptor(Ex const& ex)
181 : : native_local_stream_acceptor(ex.context())
182 : {
183 : }
184 :
185 : /// Move construct.
186 2 : native_local_stream_acceptor(native_local_stream_acceptor&&) noexcept =
187 : default;
188 :
189 : /// Move assign.
190 : native_local_stream_acceptor&
191 : operator=(native_local_stream_acceptor&&) noexcept = default;
192 :
193 : native_local_stream_acceptor(native_local_stream_acceptor const&) = delete;
194 : native_local_stream_acceptor&
195 : operator=(native_local_stream_acceptor const&) = delete;
196 :
197 : /** Asynchronously accept an incoming connection.
198 :
199 : Calls the backend implementation directly, bypassing virtual
200 : dispatch. Otherwise identical to @ref local_stream_acceptor::accept.
201 :
202 : @param peer The socket to receive the accepted connection.
203 :
204 : @return An awaitable yielding `io_result<>`.
205 :
206 : A closed acceptor reports `errc::bad_file_descriptor`.
207 :
208 : Both this acceptor and @p peer must outlive the returned
209 : awaitable.
210 : */
211 8 : [[nodiscard]] auto accept(local_stream_socket& peer)
212 : {
213 8 : native_accept_awaitable aw(*this, peer);
214 8 : if (!is_open())
215 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
216 8 : return aw;
217 : }
218 :
219 : /** Asynchronously accept an incoming connection, returning the peer.
220 :
221 : Calls the backend implementation directly, bypassing virtual
222 : dispatch. The accepted peer is returned as a
223 : @ref native_local_stream_socket so that subsequent I/O on it
224 : is also devirtualized.
225 :
226 : @return An awaitable yielding
227 : `io_result<native_local_stream_socket<Backend>>`.
228 :
229 : A closed acceptor reports `errc::bad_file_descriptor`.
230 :
231 : @throws std::logic_error If the acceptor has been moved from.
232 :
233 : This acceptor must outlive the returned awaitable.
234 : */
235 8 : [[nodiscard]] auto accept()
236 : {
237 : // The awaitable builds the peer from context(), which a
238 : // moved-from acceptor no longer has.
239 8 : if (!h_)
240 2 : detail::throw_logic_error("accept: acceptor moved-from");
241 6 : native_move_accept_awaitable aw(*this);
242 6 : if (!is_open())
243 2 : aw.ec_ = make_error_code(std::errc::bad_file_descriptor);
244 6 : return aw;
245 : }
246 :
247 : /** Asynchronously wait for the acceptor to be ready.
248 :
249 : Calls the backend implementation directly, bypassing virtual
250 : dispatch. Otherwise identical to @ref local_stream_acceptor::wait.
251 :
252 : @param w The wait direction (typically `wait_type::read`).
253 :
254 : @return An awaitable yielding `io_result<>`.
255 : */
256 6 : [[nodiscard]] auto wait(wait_type w)
257 : {
258 6 : return native_wait_awaitable(*this, w);
259 : }
260 : };
261 :
262 : } // namespace boost::corosio
263 :
264 : #endif // BOOST_COROSIO_NATIVE_NATIVE_LOCAL_STREAM_ACCEPTOR_HPP
|