92.86% Lines (39/42) 100.00% Functions (13/13)
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_TCP_ACCEPTOR_HPP 10   #ifndef BOOST_COROSIO_NATIVE_NATIVE_TCP_ACCEPTOR_HPP
11   #define BOOST_COROSIO_NATIVE_NATIVE_TCP_ACCEPTOR_HPP 11   #define BOOST_COROSIO_NATIVE_NATIVE_TCP_ACCEPTOR_HPP
12   12  
13   #include <boost/corosio/tcp_acceptor.hpp> 13   #include <boost/corosio/tcp_acceptor.hpp>
14   #include <boost/corosio/backend.hpp> 14   #include <boost/corosio/backend.hpp>
15   15  
16   #ifndef BOOST_COROSIO_MRDOCS 16   #ifndef BOOST_COROSIO_MRDOCS
17   #if BOOST_COROSIO_HAS_EPOLL 17   #if BOOST_COROSIO_HAS_EPOLL
18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp> 18   #include <boost/corosio/native/detail/epoll/epoll_types.hpp>
19   #endif 19   #endif
20   20  
21   #if BOOST_COROSIO_HAS_SELECT 21   #if BOOST_COROSIO_HAS_SELECT
22   #include <boost/corosio/native/detail/select/select_types.hpp> 22   #include <boost/corosio/native/detail/select/select_types.hpp>
23   #endif 23   #endif
24   24  
25   #if BOOST_COROSIO_HAS_KQUEUE 25   #if BOOST_COROSIO_HAS_KQUEUE
26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp> 26   #include <boost/corosio/native/detail/kqueue/kqueue_types.hpp>
27   #endif 27   #endif
28   28  
29   #if BOOST_COROSIO_HAS_IOCP 29   #if BOOST_COROSIO_HAS_IOCP
30   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp> 30   #include <boost/corosio/native/detail/iocp/win_tcp_acceptor_service.hpp>
31   #endif 31   #endif
  32 +
  33 + #if BOOST_COROSIO_HAS_IO_URING
  34 + #include <boost/corosio/native/detail/io_uring/io_uring_types.hpp>
  35 + #endif
32   #endif // !BOOST_COROSIO_MRDOCS 36   #endif // !BOOST_COROSIO_MRDOCS
33   37  
34   namespace boost::corosio { 38   namespace boost::corosio {
35   39  
36   /** An asynchronous TCP acceptor with devirtualized accept operations. 40   /** An asynchronous TCP acceptor with devirtualized accept operations.
37   41  
38   This class template inherits from @ref tcp_acceptor and shadows 42   This class template inherits from @ref tcp_acceptor and shadows
39   the `accept` operation with a version that calls the backend 43   the `accept` operation with a version that calls the backend
40   implementation directly, allowing the compiler to inline through 44   implementation directly, allowing the compiler to inline through
41   the entire call chain. 45   the entire call chain.
42   46  
43   Non-async operations (`listen`, `close`, `cancel`) remain 47   Non-async operations (`listen`, `close`, `cancel`) remain
44   unchanged and dispatch through the compiled library. 48   unchanged and dispatch through the compiled library.
45   49  
46   A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed 50   A `native_tcp_acceptor` IS-A `tcp_acceptor` and can be passed
47   to any function expecting `tcp_acceptor&`. 51   to any function expecting `tcp_acceptor&`.
48   52  
49   @tparam Backend A backend tag value (e.g., `epoll`). 53   @tparam Backend A backend tag value (e.g., `epoll`).
50   54  
51   @par Thread Safety 55   @par Thread Safety
52   Same as @ref tcp_acceptor. 56   Same as @ref tcp_acceptor.
53   57  
54   @see tcp_acceptor, epoll_t, iocp_t 58   @see tcp_acceptor, epoll_t, iocp_t
55   */ 59   */
56   template<auto Backend> 60   template<auto Backend>
57   class native_tcp_acceptor : public tcp_acceptor 61   class native_tcp_acceptor : public tcp_acceptor
58   { 62   {
59   using backend_type = decltype(Backend); 63   using backend_type = decltype(Backend);
60   using impl_type = typename backend_type::tcp_acceptor_type; 64   using impl_type = typename backend_type::tcp_acceptor_type;
61   using service_type = typename backend_type::tcp_acceptor_service_type; 65   using service_type = typename backend_type::tcp_acceptor_service_type;
62   66  
HITCBC 63   10 impl_type& get_impl() noexcept 67   10 impl_type& get_impl() noexcept
64   { 68   {
HITCBC 65   10 return *static_cast<impl_type*>(h_.get()); 69   10 return *static_cast<impl_type*>(h_.get());
66   } 70   }
67   71  
68   struct native_wait_awaitable 72   struct native_wait_awaitable
69   { 73   {
70   native_tcp_acceptor& acc_; 74   native_tcp_acceptor& acc_;
71   wait_type w_; 75   wait_type w_;
72   std::stop_token token_; 76   std::stop_token token_;
73   mutable std::error_code ec_; 77   mutable std::error_code ec_;
74   78  
HITCBC 75   2 native_wait_awaitable(native_tcp_acceptor& acc, wait_type w) noexcept 79   2 native_wait_awaitable(native_tcp_acceptor& acc, wait_type w) noexcept
HITCBC 76   2 : acc_(acc) 80   2 : acc_(acc)
HITCBC 77   2 , w_(w) 81   2 , w_(w)
78   { 82   {
HITCBC 79   2 } 83   2 }
80   84  
HITCBC 81   2 bool await_ready() const noexcept 85   2 bool await_ready() const noexcept
82   { 86   {
HITCBC 83   2 return token_.stop_requested(); 87   2 return token_.stop_requested();
84   } 88   }
85   89  
HITCBC 86   2 capy::io_result<> await_resume() const noexcept 90   2 capy::io_result<> await_resume() const noexcept
87   { 91   {
HITCBC 88   2 if (token_.stop_requested()) 92   2 if (token_.stop_requested())
MISUBC 89   return {make_error_code(std::errc::operation_canceled)}; 93   return {make_error_code(std::errc::operation_canceled)};
HITCBC 90   2 return {ec_}; 94   2 return {ec_};
91   } 95   }
92   96  
HITCBC 93   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 97   2 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
94   -> std::coroutine_handle<> 98   -> std::coroutine_handle<>
95   { 99   {
HITCBC 96   2 token_ = env->stop_token; 100   2 token_ = env->stop_token;
HITCBC 97   6 return acc_.get_impl().wait( 101   6 return acc_.get_impl().wait(
HITCBC 98   6 h, env->executor, w_, token_, &ec_); 102   6 h, env->executor, w_, token_, &ec_);
99   } 103   }
100   }; 104   };
101   105  
102   struct native_accept_awaitable 106   struct native_accept_awaitable
103   { 107   {
104   native_tcp_acceptor& acc_; 108   native_tcp_acceptor& acc_;
105   tcp_socket& peer_; 109   tcp_socket& peer_;
106   std::stop_token token_; 110   std::stop_token token_;
107   mutable std::error_code ec_; 111   mutable std::error_code ec_;
108   mutable io_object::implementation* peer_impl_ = nullptr; 112   mutable io_object::implementation* peer_impl_ = nullptr;
109   113  
HITCBC 110   8 native_accept_awaitable( 114   8 native_accept_awaitable(
111   native_tcp_acceptor& acc, tcp_socket& peer) noexcept 115   native_tcp_acceptor& acc, tcp_socket& peer) noexcept
HITCBC 112   8 : acc_(acc) 116   8 : acc_(acc)
HITCBC 113   8 , peer_(peer) 117   8 , peer_(peer)
114   { 118   {
HITCBC 115   8 } 119   8 }
116   120  
HITCBC 117   8 bool await_ready() const noexcept 121   8 bool await_ready() const noexcept
118   { 122   {
HITCBC 119   8 return token_.stop_requested(); 123   8 return token_.stop_requested();
120   } 124   }
121   125  
HITCBC 122   8 capy::io_result<> await_resume() const noexcept 126   8 capy::io_result<> await_resume() const noexcept
123   { 127   {
HITCBC 124   8 if (token_.stop_requested()) 128   8 if (token_.stop_requested())
MISUBC 125   return {make_error_code(std::errc::operation_canceled)}; 129   return {make_error_code(std::errc::operation_canceled)};
HITCBC 126   8 if (!ec_) 130   8 if (!ec_)
HITCBC 127   8 acc_.reset_peer_impl(peer_, peer_impl_); 131   8 acc_.reset_peer_impl(peer_, peer_impl_);
HITCBC 128   8 return {ec_}; 132   8 return {ec_};
129   } 133   }
130   134  
HITCBC 131   8 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env) 135   8 auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
132   -> std::coroutine_handle<> 136   -> std::coroutine_handle<>
133   { 137   {
HITCBC 134   8 token_ = env->stop_token; 138   8 token_ = env->stop_token;
HITCBC 135   24 return acc_.get_impl().accept( 139   24 return acc_.get_impl().accept(
HITCBC 136   24 h, env->executor, token_, &ec_, &peer_impl_); 140   24 h, env->executor, token_, &ec_, &peer_impl_);
137   } 141   }
138   }; 142   };
139   143  
140   public: 144   public:
141   /** Construct a native acceptor from an execution context. 145   /** Construct a native acceptor from an execution context.
142   146  
143   @param ctx The execution context that will own this acceptor. 147   @param ctx The execution context that will own this acceptor.
144   */ 148   */
HITCBC 145   18 explicit native_tcp_acceptor(capy::execution_context& ctx) 149   18 explicit native_tcp_acceptor(capy::execution_context& ctx)
HITCBC 146   18 : tcp_acceptor(create_handle<service_type>(ctx)) 150   18 : tcp_acceptor(create_handle<service_type>(ctx))
147   { 151   {
HITCBC 148   18 } 152   18 }
149   153  
150   /** Construct a native acceptor from an executor. 154   /** Construct a native acceptor from an executor.
151   155  
152   @param ex The executor whose context will own the acceptor. 156   @param ex The executor whose context will own the acceptor.
153   */ 157   */
154   template<class Ex> 158   template<class Ex>
155   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) && 159   requires(!std::same_as<std::remove_cvref_t<Ex>, native_tcp_acceptor>) &&
156   capy::Executor<Ex> 160   capy::Executor<Ex>
157   explicit native_tcp_acceptor(Ex const& ex) 161   explicit native_tcp_acceptor(Ex const& ex)
158   : native_tcp_acceptor(ex.context()) 162   : native_tcp_acceptor(ex.context())
159   { 163   {
160   } 164   }
161   165  
162   /** Move construct. 166   /** Move construct.
163   167  
164   @param other The acceptor to move from. 168   @param other The acceptor to move from.
165   169  
166   @pre No awaitables returned by @p other's methods exist. 170   @pre No awaitables returned by @p other's methods exist.
167   @pre The execution context associated with @p other must 171   @pre The execution context associated with @p other must
168   outlive this acceptor. 172   outlive this acceptor.
169   */ 173   */
HITCBC 170   2 native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default; 174   2 native_tcp_acceptor(native_tcp_acceptor&&) noexcept = default;
171   175  
172   /** Move assign. 176   /** Move assign.
173   177  
174   @param other The acceptor to move from. 178   @param other The acceptor to move from.
175   179  
176   @pre No awaitables returned by either `*this` or @p other's 180   @pre No awaitables returned by either `*this` or @p other's
177   methods exist. 181   methods exist.
178   @pre The execution context associated with @p other must 182   @pre The execution context associated with @p other must
179   outlive this acceptor. 183   outlive this acceptor.
180   */ 184   */
181   native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default; 185   native_tcp_acceptor& operator=(native_tcp_acceptor&&) noexcept = default;
182   186  
183   native_tcp_acceptor(native_tcp_acceptor const&) = delete; 187   native_tcp_acceptor(native_tcp_acceptor const&) = delete;
184   native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete; 188   native_tcp_acceptor& operator=(native_tcp_acceptor const&) = delete;
185   189  
186   /** Asynchronously accept an incoming connection. 190   /** Asynchronously accept an incoming connection.
187   191  
188   Calls the backend implementation directly, bypassing virtual 192   Calls the backend implementation directly, bypassing virtual
189   dispatch. Otherwise identical to @ref tcp_acceptor::accept. 193   dispatch. Otherwise identical to @ref tcp_acceptor::accept.
190   194  
191   @param peer The socket to receive the accepted connection. 195   @param peer The socket to receive the accepted connection.
192   196  
193   @return An awaitable yielding `io_result<>`. 197   @return An awaitable yielding `io_result<>`.
194   198  
195   @throws std::logic_error if the acceptor is not listening. 199   @throws std::logic_error if the acceptor is not listening.
196   200  
197   Both this acceptor and @p peer must outlive the returned 201   Both this acceptor and @p peer must outlive the returned
198   awaitable. 202   awaitable.
199   */ 203   */
HITCBC 200   8 auto accept(tcp_socket& peer) 204   8 auto accept(tcp_socket& peer)
201   { 205   {
HITCBC 202   8 if (!is_open()) 206   8 if (!is_open())
MISUBC 203   detail::throw_logic_error("accept: acceptor not listening"); 207   detail::throw_logic_error("accept: acceptor not listening");
HITCBC 204   8 return native_accept_awaitable(*this, peer); 208   8 return native_accept_awaitable(*this, peer);
205   } 209   }
206   210  
207   /** Asynchronously wait for the acceptor to be ready. 211   /** Asynchronously wait for the acceptor to be ready.
208   212  
209   Calls the backend implementation directly, bypassing virtual 213   Calls the backend implementation directly, bypassing virtual
210   dispatch. Otherwise identical to @ref tcp_acceptor::wait. 214   dispatch. Otherwise identical to @ref tcp_acceptor::wait.
211   215  
212   @param w The wait direction (typically `wait_type::read`). 216   @param w The wait direction (typically `wait_type::read`).
213   217  
214   @return An awaitable yielding `io_result<>`. 218   @return An awaitable yielding `io_result<>`.
215   */ 219   */
HITCBC 216   2 [[nodiscard]] auto wait(wait_type w) 220   2 [[nodiscard]] auto wait(wait_type w)
217   { 221   {
HITCBC 218   2 return native_wait_awaitable(*this, w); 222   2 return native_wait_awaitable(*this, w);
219   } 223   }
220   }; 224   };
221   225  
222   } // namespace boost::corosio 226   } // namespace boost::corosio
223   227  
224   #endif 228   #endif