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 4638 : reactor_acceptor_impl<
43 : Derived,
44 : Traits,
45 : Service,
46 : SocketFinal,
47 : AccImplBase,
48 : Endpoint>::
49 : accept(
50 : std::coroutine_handle<> h,
51 : capy::executor_ref ex,
52 : std::stop_token token,
53 : std::error_code* ec,
54 : io_object::implementation** impl_out)
55 : {
56 4638 : auto& op = this->acc_;
57 4638 : op.reset();
58 4638 : op.h = h;
59 4638 : op.ex = ex;
60 4638 : op.ec_out = ec;
61 4638 : op.impl_out = impl_out;
62 4638 : op.fd = this->fd_;
63 4638 : op.start(token, static_cast<Derived*>(this));
64 :
65 4638 : sockaddr_storage peer_storage{};
66 4638 : socklen_t peer_addrlen = 0;
67 :
68 : int accepted =
69 4638 : Traits::accept_policy::do_accept(this->fd_, peer_storage, peer_addrlen);
70 :
71 4638 : if (accepted >= 0)
72 : {
73 : {
74 44 : std::lock_guard lock(this->desc_state_.mutex);
75 44 : this->desc_state_.read_ready = false;
76 44 : }
77 :
78 44 : if (this->svc_.scheduler().try_consume_inline_budget())
79 : {
80 15 : auto* socket_svc = this->svc_.stream_service();
81 15 : if (socket_svc)
82 : {
83 : auto& impl =
84 15 : static_cast<SocketFinal&>(*socket_svc->construct());
85 15 : impl.set_socket(accepted);
86 :
87 15 : impl.desc_state_.fd = accepted;
88 : {
89 15 : std::lock_guard lock(impl.desc_state_.mutex);
90 15 : impl.desc_state_.read_op = nullptr;
91 15 : impl.desc_state_.write_op = nullptr;
92 15 : impl.desc_state_.connect_op = nullptr;
93 15 : }
94 15 : auto reg_ec = socket_svc->scheduler().register_descriptor(
95 : accepted, &impl.desc_state_);
96 15 : 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 14 : impl.set_endpoints(
107 : this->local_endpoint_,
108 14 : from_sockaddr_as(
109 : peer_storage, peer_addrlen, Endpoint{}));
110 :
111 14 : *ec = {};
112 14 : if (impl_out)
113 14 : *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 HIT 15 : op.cont.h = h;
124 15 : return dispatch_coro(ex, op.cont);
125 : }
126 :
127 29 : op.accepted_fd = accepted;
128 29 : op.peer_storage = peer_storage;
129 29 : op.peer_addrlen = peer_addrlen;
130 29 : op.complete(0, 0);
131 29 : op.impl_ptr = this->shared_from_this();
132 29 : this->svc_.post(&op);
133 29 : return std::noop_coroutine();
134 : }
135 :
136 4594 : if (errno == EAGAIN || errno == EWOULDBLOCK)
137 : {
138 4584 : op.impl_ptr = this->shared_from_this();
139 4584 : this->svc_.work_started();
140 :
141 4584 : std::lock_guard lock(this->desc_state_.mutex);
142 4584 : bool io_done = false;
143 4584 : if (this->desc_state_.read_ready)
144 : {
145 MIS 0 : this->desc_state_.read_ready = false;
146 0 : op.perform_io();
147 0 : io_done = (op.errn != EAGAIN && op.errn != EWOULDBLOCK);
148 0 : if (!io_done)
149 0 : op.errn = 0;
150 : }
151 :
152 HIT 4584 : if (io_done || op.cancelled.load(std::memory_order_acquire))
153 : {
154 10 : this->svc_.post(&op);
155 10 : this->svc_.work_finished();
156 : }
157 : else
158 : {
159 4574 : this->desc_state_.read_op = &op;
160 : }
161 4584 : return std::noop_coroutine();
162 4584 : }
163 :
164 10 : op.complete(errno, 0);
165 10 : op.impl_ptr = this->shared_from_this();
166 10 : this->svc_.post(&op);
167 10 : return std::noop_coroutine();
168 : }
169 :
170 : } // namespace boost::corosio::detail
171 :
172 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_BACKEND_HPP
|