TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
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_DETAIL_REACTOR_REACTOR_BACKEND_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_BACKEND_HPP
12 :
13 : /* Reactor backend: acceptor accept() implementation.
14 :
15 : Contains the accept() method body for reactor_acceptor_impl,
16 : which needs all socket/service types to be complete. Included
17 : by per-backend type files (epoll_types.hpp, etc.) after all
18 : named types are defined.
19 : */
20 :
21 : #include <boost/corosio/native/detail/reactor/reactor_service_finals.hpp>
22 : #include <boost/corosio/native/detail/reactor/reactor_op_complete.hpp>
23 : #include <boost/corosio/native/detail/endpoint_convert.hpp>
24 : #include <boost/corosio/detail/dispatch_coro.hpp>
25 :
26 : #include <mutex>
27 :
28 : namespace boost::corosio::detail {
29 :
30 : // ============================================================
31 : // Acceptor accept() implementation
32 : // ============================================================
33 :
34 : template<
35 : class Derived,
36 : class Traits,
37 : class Service,
38 : class SocketFinal,
39 : class AccImplBase,
40 : class Endpoint>
41 : std::coroutine_handle<>
42 HIT 7490 : reactor_acceptor_impl<
43 : Derived,
44 : Traits,
45 : Service,
46 : SocketFinal,
47 : AccImplBase,
48 : Endpoint>::
49 : accept(
50 : capy::continuation& cont,
51 : capy::executor_ref ex,
52 : std::stop_token token,
53 : std::error_code* ec,
54 : io_object::implementation** impl_out)
55 : {
56 7490 : auto& op = this->acc_;
57 7490 : op.reset();
58 7490 : op.cont = &cont;
59 7490 : op.ex = ex;
60 7490 : op.ec_out = ec;
61 7490 : op.impl_out = impl_out;
62 7490 : op.fd = this->fd_;
63 7490 : op.start(token, static_cast<Derived*>(this));
64 :
65 7490 : sockaddr_storage peer_storage{};
66 7490 : socklen_t peer_addrlen = 0;
67 :
68 : int accepted =
69 7490 : Traits::accept_policy::do_accept(this->fd_, peer_storage, peer_addrlen);
70 :
71 7490 : if (accepted >= 0)
72 : {
73 : {
74 758 : std::lock_guard lock(this->desc_state_.mutex);
75 758 : this->desc_state_.read_ready = false;
76 758 : }
77 :
78 758 : if (this->svc_.scheduler().try_consume_inline_budget())
79 : {
80 586 : auto* socket_svc = this->svc_.stream_service();
81 586 : if (socket_svc)
82 : {
83 : auto& impl =
84 586 : static_cast<SocketFinal&>(*socket_svc->construct());
85 586 : impl.set_socket(accepted);
86 :
87 586 : impl.desc_state_.fd = accepted;
88 : {
89 586 : std::lock_guard lock(impl.desc_state_.mutex);
90 586 : impl.desc_state_.read_op = nullptr;
91 586 : impl.desc_state_.write_op = nullptr;
92 586 : impl.desc_state_.connect_op = nullptr;
93 586 : }
94 586 : auto reg_ec = socket_svc->scheduler().register_descriptor(
95 : accepted, &impl.desc_state_);
96 586 : if (reg_ec)
97 : {
98 : // destroy() closes the fd the impl already owns.
99 1 : socket_svc->destroy(&impl);
100 1 : *ec = reg_ec;
101 1 : if (impl_out)
102 1 : *impl_out = nullptr;
103 : }
104 : else
105 : {
106 585 : impl.set_endpoints(
107 : this->local_endpoint_,
108 585 : from_sockaddr_as(
109 : peer_storage, peer_addrlen, Endpoint{}));
110 :
111 585 : *ec = {};
112 585 : if (impl_out)
113 585 : *impl_out = &impl;
114 : }
115 : }
116 : else
117 : {
118 MIS 0 : ::close(accepted);
119 0 : *ec = make_err(ENOENT);
120 0 : if (impl_out)
121 0 : *impl_out = nullptr;
122 : }
123 : // Completed without parking: nothing left for a stop to cancel.
124 HIT 586 : op.stop_cb.reset();
125 586 : return dispatch_coro(ex, cont);
126 : }
127 :
128 172 : op.accepted_fd = accepted;
129 172 : op.peer_storage = peer_storage;
130 172 : op.peer_addrlen = peer_addrlen;
131 172 : op.complete(0, 0);
132 172 : op.object_ref_ = detail::object_ref(this);
133 172 : this->svc_.post(&op);
134 172 : return std::noop_coroutine();
135 : }
136 :
137 6732 : if (errno == EAGAIN || errno == EWOULDBLOCK)
138 : {
139 6722 : op.object_ref_ = detail::object_ref(this);
140 6722 : this->svc_.work_started();
141 :
142 : // Posted after the descriptor lock is released: the scheduler
143 : // takes its own lock before descriptor locks.
144 6722 : bool post_now = false;
145 : {
146 6722 : std::lock_guard lock(this->desc_state_.mutex);
147 6722 : bool io_done = false;
148 6722 : if (this->desc_state_.read_ready)
149 : {
150 1 : this->desc_state_.read_ready = false;
151 1 : op.perform_io();
152 1 : io_done = (op.errn != EAGAIN && op.errn != EWOULDBLOCK);
153 1 : if (!io_done)
154 1 : op.errn = 0;
155 : }
156 :
157 6722 : if (io_done || op.cancelled.load(std::memory_order_acquire))
158 : {
159 MIS 0 : post_now = true;
160 : }
161 : else
162 : {
163 HIT 6722 : this->desc_state_.read_op = &op;
164 : // Select watches reads only for parked ops; see
165 : // park_op.
166 : if constexpr (Traits::needs_park_notification)
167 3040 : this->svc_.scheduler().notify_reactor();
168 : }
169 6722 : }
170 6722 : if (post_now)
171 MIS 0 : this->svc_.scheduler().post_counted(&op);
172 HIT 6722 : return std::noop_coroutine();
173 : }
174 :
175 10 : op.complete(errno, 0);
176 10 : op.object_ref_ = detail::object_ref(this);
177 10 : this->svc_.post(&op);
178 10 : return std::noop_coroutine();
179 : }
180 :
181 : } // namespace boost::corosio::detail
182 :
183 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_BACKEND_HPP
|