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