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