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