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_DESCRIPTOR_SERVICE_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_DESCRIPTOR_SERVICE_HPP
12 :
13 : #include <boost/corosio/detail/platform.hpp>
14 :
15 : #if BOOST_COROSIO_POSIX
16 :
17 : #include <boost/corosio/detail/descriptor_service.hpp>
18 : #include <boost/corosio/detail/scheduler_op.hpp>
19 : #include <boost/corosio/native/detail/validate_fd.hpp>
20 : #include <boost/corosio/native/detail/reactor/reactor_descriptor.hpp>
21 : #include <boost/corosio/native/detail/reactor/reactor_service_state.hpp>
22 : #include <boost/capy/ex/execution_context.hpp>
23 :
24 : #include <memory>
25 : #include <mutex>
26 : #include <system_error>
27 :
28 : /* Reactor-backed descriptor_service.
29 :
30 : assign_descriptor is the validate-before-mutate core the public
31 : assign() contract rests on, modelled on do_assign_fd in
32 : reactor_service_finals.hpp.
33 :
34 : PARALLEL COPY: construct, destroy, close and shutdown here mirror the
35 : same four members of reactor_socket_service.hpp, which this cannot
36 : reuse because it calls close_socket() by name. A fix to the service
37 : lifecycle -- the pool's acquire/recycle, or shutdown's reliance on
38 : queued ops holding their own reference through the scheduler's
39 : drain -- belongs in both files.
40 : */
41 :
42 : namespace boost::corosio::detail {
43 :
44 : /** CRTP base for reactor-backed descriptor services.
45 :
46 : @tparam Derived The named final service type (CRTP self).
47 : @tparam Traits Backend traits (epoll_traits, kqueue_traits, ...).
48 : @tparam DescFinal The named final descriptor impl type.
49 : */
50 : template<class Derived, class Traits, class DescFinal>
51 : class reactor_descriptor_service : public descriptor_service
52 : {
53 : using scheduler_type = typename Traits::scheduler_type;
54 : using state_type = reactor_service_state<scheduler_type, DescFinal>;
55 :
56 : friend Derived;
57 :
58 : // The CRTP base reaches into state_->pool_ from retire().
59 : template<class, class, class, class>
60 : friend class reactor_descriptor;
61 :
62 : protected:
63 : // NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
64 HIT 117 : explicit reactor_descriptor_service(capy::execution_context& ctx)
65 117 : : state_(
66 : std::make_unique<state_type>(
67 117 : ctx.template use_service<scheduler_type>()))
68 : {
69 117 : }
70 :
71 : public:
72 : /// True when any parked op must wake the reactor.
73 : static constexpr bool needs_park_notification =
74 : Traits::needs_park_notification;
75 :
76 117 : ~reactor_descriptor_service() override = default;
77 :
78 : std::error_code assign_descriptor(
79 : posix_stream_descriptor::implementation& impl,
80 : native_handle_type fd) override;
81 :
82 117 : void shutdown() override
83 : {
84 117 : state_->pool_.shutdown(
85 135 : [](DescFinal* impl) { impl->close_descriptor(); });
86 :
87 : // See reactor_socket_service::shutdown(): queued ops hold their
88 : // own reference; the scheduler's drain releases them after us,
89 : // and shutting-down mode deletes rather than recycles at zero.
90 117 : }
91 :
92 205 : io_object::implementation* construct() override
93 : {
94 205 : return state_->pool_.acquire(static_cast<Derived&>(*this));
95 : }
96 :
97 205 : void destroy(io_object::implementation* impl) override
98 : {
99 205 : auto* typed = static_cast<DescFinal*>(impl);
100 205 : typed->close_descriptor();
101 205 : release(typed);
102 205 : }
103 :
104 373 : void close(io_object::handle& h) override
105 : {
106 373 : static_cast<DescFinal*>(h.get())->close_descriptor();
107 373 : }
108 :
109 765 : scheduler_type& scheduler() const noexcept
110 : {
111 765 : return state_->sched_;
112 : }
113 :
114 75 : void post(scheduler_op* op)
115 : {
116 75 : state_->sched_.post(op);
117 75 : }
118 :
119 93 : void work_started() noexcept
120 : {
121 93 : state_->sched_.work_started();
122 93 : }
123 :
124 : protected:
125 : std::unique_ptr<state_type> state_;
126 :
127 : private:
128 : reactor_descriptor_service(reactor_descriptor_service const&) = delete;
129 : reactor_descriptor_service&
130 : operator=(reactor_descriptor_service const&) = delete;
131 : };
132 :
133 : template<class Derived, class Traits, class DescFinal>
134 : std::error_code
135 193 : reactor_descriptor_service<Derived, Traits, DescFinal>::assign_descriptor(
136 : posix_stream_descriptor::implementation& impl_base, native_handle_type fd)
137 : {
138 193 : auto* impl = static_cast<DescFinal*>(&impl_base);
139 :
140 : // The public assign() guarantees the object is closed.
141 193 : if (auto ec = validate_descriptor_fd(fd))
142 4 : return ec;
143 :
144 : if constexpr (requires { Traits::max_descriptor; })
145 : {
146 94 : if (fd >= Traits::max_descriptor)
147 1 : return make_err(EMFILE);
148 : }
149 :
150 188 : return impl->init_and_register(fd);
151 : }
152 :
153 : } // namespace boost::corosio::detail
154 :
155 : #endif // BOOST_COROSIO_POSIX
156 :
157 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_DESCRIPTOR_SERVICE_HPP
|