TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Steve Gerbino
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_SOCKET_SERVICE_HPP
11 : #define BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SOCKET_SERVICE_HPP
12 :
13 : #include <boost/corosio/io/io_object.hpp>
14 : #include <boost/corosio/detail/scheduler_op.hpp>
15 : #include <boost/corosio/native/detail/reactor/reactor_service_state.hpp>
16 : #include <boost/capy/ex/execution_context.hpp>
17 :
18 : #include <memory>
19 : #include <mutex>
20 :
21 : namespace boost::corosio::detail {
22 :
23 : /** CRTP base for reactor-backed socket/datagram service implementations.
24 :
25 : Provides the shared construct/destroy/shutdown/close/post/work
26 : logic that is identical across all reactor backends and socket
27 : types. Derived classes add only protocol-specific open/bind.
28 :
29 : @tparam Derived The concrete service type (CRTP).
30 : @tparam ServiceBase The abstract service base (tcp_service
31 : or udp_service).
32 : @tparam Scheduler The backend's scheduler type.
33 : @tparam Impl The backend's socket/datagram impl type.
34 : */
35 : template<class Derived, class ServiceBase, class Scheduler, class Impl>
36 : class reactor_socket_service : public ServiceBase
37 : {
38 : friend Derived;
39 : using state_type = reactor_service_state<Scheduler, Impl>;
40 :
41 : public:
42 : /// Propagated from Scheduler for register_op's write notification.
43 : static constexpr bool needs_write_notification =
44 : Scheduler::needs_write_notification;
45 :
46 : private:
47 :
48 HIT 2348 : explicit reactor_socket_service(capy::execution_context& ctx)
49 2348 : : state_(
50 : std::make_unique<state_type>(
51 2348 : ctx.template use_service<Scheduler>()))
52 : {
53 2348 : }
54 :
55 : public:
56 2348 : ~reactor_socket_service() override = default;
57 :
58 2348 : void shutdown() override
59 : {
60 2348 : std::lock_guard lock(state_->mutex_);
61 :
62 2348 : while (auto* impl = state_->impl_list_.pop_front())
63 : {
64 MIS 0 : static_cast<Derived*>(this)->pre_shutdown(impl);
65 0 : impl->close_socket();
66 : }
67 :
68 : // Don't clear impl_ptrs_ here. The scheduler shuts down after us
69 : // and drains completed_ops_, calling destroy() on each queued op.
70 : // Letting ~state_ release the ptrs (during service destruction,
71 : // after scheduler shutdown) keeps every impl alive until all ops
72 : // have been drained.
73 HIT 2348 : }
74 :
75 25797 : io_object::implementation* construct() override
76 : {
77 25797 : auto impl = std::make_shared<Impl>(static_cast<Derived&>(*this));
78 25797 : auto* raw = impl.get();
79 :
80 : {
81 25797 : std::lock_guard lock(state_->mutex_);
82 25797 : state_->impl_ptrs_.emplace(raw, std::move(impl));
83 25797 : state_->impl_list_.push_back(raw);
84 25797 : }
85 :
86 25797 : return raw;
87 25797 : }
88 :
89 25797 : void destroy(io_object::implementation* impl) override
90 : {
91 25797 : auto* typed = static_cast<Impl*>(impl);
92 25797 : static_cast<Derived*>(this)->pre_destroy(typed);
93 25797 : typed->close_socket();
94 25797 : std::lock_guard lock(state_->mutex_);
95 25797 : state_->impl_list_.remove(typed);
96 25797 : state_->impl_ptrs_.erase(typed);
97 25797 : }
98 :
99 43007 : void close(io_object::handle& h) override
100 : {
101 43007 : static_cast<Impl*>(h.get())->close_socket();
102 43007 : }
103 :
104 443865 : Scheduler& scheduler() const noexcept
105 : {
106 443865 : return state_->sched_;
107 : }
108 :
109 81457 : void post(scheduler_op* op)
110 : {
111 81457 : state_->sched_.post(op);
112 81457 : }
113 :
114 8915 : void work_started() noexcept
115 : {
116 8915 : state_->sched_.work_started();
117 8915 : }
118 :
119 299 : void work_finished() noexcept
120 : {
121 299 : state_->sched_.work_finished();
122 299 : }
123 :
124 : protected:
125 : // Override in derived to add pre-close logic (e.g. kqueue linger reset)
126 MIS 0 : void pre_shutdown(Impl*) noexcept {}
127 HIT 154 : void pre_destroy(Impl*) noexcept {}
128 :
129 : std::unique_ptr<state_type> state_;
130 :
131 : private:
132 : reactor_socket_service(reactor_socket_service const&) = delete;
133 : reactor_socket_service& operator=(reactor_socket_service const&) = delete;
134 : };
135 :
136 : } // namespace boost::corosio::detail
137 :
138 : #endif // BOOST_COROSIO_NATIVE_DETAIL_REACTOR_REACTOR_SOCKET_SERVICE_HPP
|