TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Steve Gerbino
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_IO_IO_OBJECT_HPP
12 : #define BOOST_COROSIO_IO_IO_OBJECT_HPP
13 :
14 : #include <boost/corosio/detail/config.hpp>
15 : #include <boost/corosio/detail/except.hpp>
16 : #include <boost/capy/ex/execution_context.hpp>
17 :
18 : #include <utility>
19 :
20 : namespace boost::corosio {
21 :
22 : /** Base class for platform I/O objects.
23 :
24 : Provides common infrastructure for I/O objects that wrap kernel
25 : resources (sockets, timers, signal handlers, acceptors). Derived
26 : classes dispatch operations through a platform-specific vtable
27 : (IOCP, epoll, kqueue, io_uring).
28 :
29 : @par Semantics
30 : Only concrete platform I/O types should inherit from `io_object`.
31 : Test mocks, decorators, and stream adapters must not inherit from
32 : this class. Use concepts or templates for generic I/O algorithms.
33 :
34 : @par Thread Safety
35 : Distinct objects: Safe.
36 : Shared objects: Unsafe. All operations on a single I/O object
37 : must be serialized.
38 :
39 : @note Intended as a protected base class. The handle member
40 : `h_` is accessible to derived classes.
41 :
42 : @see io_stream, tcp_socket, tcp_acceptor
43 : */
44 : class BOOST_COROSIO_DECL io_object
45 : {
46 : public:
47 : class handle;
48 :
49 : /** Base interface for platform I/O implementations.
50 :
51 : Derived classes provide platform-specific operation dispatch.
52 : */
53 : struct implementation
54 : {
55 HIT 23679 : virtual ~implementation() = default;
56 : };
57 :
58 : /** Service interface for I/O object lifecycle management.
59 :
60 : Platform backends implement this interface to manage the
61 : creation, closing, and destruction of I/O object
62 : implementations.
63 : */
64 : struct io_service
65 : {
66 1700 : virtual ~io_service() = default;
67 :
68 : /// Construct a new implementation instance.
69 : virtual implementation* construct() = 0;
70 :
71 : /// Destroy the implementation, closing kernel resources and freeing memory.
72 : virtual void destroy(implementation*) = 0;
73 :
74 : /// Close the I/O object, releasing kernel resources without deallocating.
75 8592 : virtual void close(handle&) {}
76 : };
77 :
78 : /** RAII wrapper for I/O object implementation lifetime.
79 :
80 : Manages ownership of the platform-specific implementation,
81 : automatically destroying it when the handle goes out of scope.
82 : */
83 : class handle
84 : {
85 : capy::execution_context* ctx_ = nullptr;
86 : io_service* svc_ = nullptr;
87 : implementation* impl_ = nullptr;
88 :
89 : public:
90 : /// Destroy the handle and its implementation.
91 57258 : ~handle()
92 : {
93 57258 : if (impl_)
94 : {
95 24226 : svc_->close(*this);
96 24226 : svc_->destroy(impl_);
97 : }
98 57258 : }
99 :
100 : /// Construct an empty handle.
101 : handle() = default;
102 :
103 : /// Construct a handle bound to a context and service.
104 24248 : handle(capy::execution_context& ctx, io_service& svc)
105 24248 : : ctx_(&ctx)
106 24248 : , svc_(&svc)
107 24248 : , impl_(svc_->construct())
108 : {
109 24248 : }
110 :
111 : /// Move construct from another handle.
112 33010 : handle(handle&& other) noexcept
113 33010 : : ctx_(std::exchange(other.ctx_, nullptr))
114 33010 : , svc_(std::exchange(other.svc_, nullptr))
115 33010 : , impl_(std::exchange(other.impl_, nullptr))
116 : {
117 33010 : }
118 :
119 : /// Move assign from another handle.
120 22 : handle& operator=(handle&& other) noexcept
121 : {
122 22 : if (this != &other)
123 : {
124 22 : if (impl_)
125 : {
126 22 : svc_->close(*this);
127 22 : svc_->destroy(impl_);
128 : }
129 22 : ctx_ = std::exchange(other.ctx_, nullptr);
130 22 : svc_ = std::exchange(other.svc_, nullptr);
131 22 : impl_ = std::exchange(other.impl_, nullptr);
132 : }
133 22 : return *this;
134 : }
135 :
136 : handle(handle const&) = delete;
137 : handle& operator=(handle const&) = delete;
138 :
139 : /// Return true if the handle owns an implementation.
140 55499 : explicit operator bool() const noexcept
141 : {
142 55499 : return impl_ != nullptr;
143 : }
144 :
145 : /// Return the associated I/O service.
146 23465 : io_service& service() const noexcept
147 : {
148 23465 : return *svc_;
149 : }
150 :
151 : /// Return the platform implementation.
152 701631 : implementation* get() const noexcept
153 : {
154 701631 : return impl_;
155 : }
156 :
157 : /** Replace the implementation, destroying the old one.
158 :
159 : @param p The new implementation to own. May be nullptr.
160 : */
161 7733 : void reset(implementation* p) noexcept
162 : {
163 7733 : if (impl_)
164 : {
165 7733 : svc_->close(*this);
166 7733 : svc_->destroy(impl_);
167 : }
168 7733 : impl_ = p;
169 7733 : }
170 :
171 : /// Return the execution context.
172 10 : capy::execution_context& context() const noexcept
173 : {
174 10 : return *ctx_;
175 : }
176 : };
177 :
178 : /// Return the execution context.
179 10 : capy::execution_context& context() const noexcept
180 : {
181 10 : return h_.context();
182 : }
183 :
184 : protected:
185 24443 : virtual ~io_object() = default;
186 :
187 : /// Default construct for virtual base initialization.
188 : io_object() noexcept = default;
189 :
190 : /** Create a handle bound to a service found in the context.
191 :
192 : @tparam Service The service type whose key_type is used for lookup.
193 : @param ctx The execution context to search for the service.
194 :
195 : @return A handle owning a freshly constructed implementation.
196 :
197 : @throws std::logic_error if the service is not installed.
198 : */
199 : template<class Service>
200 15773 : static handle create_handle(capy::execution_context& ctx)
201 : {
202 15773 : auto* svc = ctx.find_service<Service>();
203 15773 : if (!svc)
204 MIS 0 : detail::throw_logic_error(
205 : "io_object::create_handle: service not installed");
206 HIT 15773 : return handle(ctx, *svc);
207 : }
208 :
209 : /// Construct an I/O object from a handle.
210 24248 : explicit io_object(handle h) noexcept : h_(std::move(h)) {}
211 :
212 : /// Move construct from another I/O object.
213 195 : io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
214 :
215 : /// Move assign from another I/O object.
216 : io_object& operator=(io_object&& other) noexcept
217 : {
218 : if (this != &other)
219 : h_ = std::move(other.h_);
220 : return *this;
221 : }
222 :
223 : io_object(io_object const&) = delete;
224 : io_object& operator=(io_object const&) = delete;
225 :
226 : handle h_;
227 : };
228 :
229 : } // namespace boost::corosio
230 :
231 : #endif
|