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