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   /** Owns the platform-specific handle and execution context that a derived
23   socket, timer, signal handler, or acceptor type uses to dispatch 23   socket, timer, signal handler, or acceptor type uses to dispatch
24   operations. 24   operations.
25   25  
26   Provides common infrastructure for I/O objects that wrap kernel 26   Provides common infrastructure for I/O objects that wrap kernel
27   resources (sockets, timers, signal handlers, acceptors). Derived 27   resources (sockets, timers, signal handlers, acceptors). Derived
28   classes dispatch operations through a platform-specific vtable 28   classes dispatch operations through a platform-specific vtable
29   (IOCP, epoll, kqueue, io_uring). 29   (IOCP, epoll, kqueue, io_uring).
30   30  
31   @par Semantics 31   @par Semantics
32   Only concrete platform I/O types should inherit from `io_object`. 32   Only concrete platform I/O types should inherit from `io_object`.
33   Test mocks, decorators, and stream adapters must not inherit from 33   Test mocks, decorators, and stream adapters must not inherit from
34   this class. Use concepts or templates for generic I/O algorithms. 34   this class. Use concepts or templates for generic I/O algorithms.
35   35  
36   @par Thread Safety 36   @par Thread Safety
37   Distinct objects: Safe. 37   Distinct objects: Safe.
38   Shared objects: Unsafe. All operations on a single I/O object 38   Shared objects: Unsafe. All operations on a single I/O object
39   must be serialized. 39   must be serialized.
40   40  
41   @note Intended as a protected base class. The handle member 41   @note Intended as a protected base class. The handle member
42   `h_` is accessible to derived classes. 42   `h_` is accessible to derived classes.
43   43  
44   @see io_stream, tcp_socket, tcp_acceptor 44   @see io_stream, tcp_socket, tcp_acceptor
45   */ 45   */
46   class BOOST_COROSIO_DECL io_object 46   class BOOST_COROSIO_DECL io_object
47   { 47   {
48   public: 48   public:
49   class handle; 49   class handle;
50   50  
51   /** Derived types dispatch platform-specific I/O operations through it. 51   /** Derived types dispatch platform-specific I/O operations through it.
52   */ 52   */
53   struct implementation 53   struct implementation
54   { 54   {
55   /// Destroy the implementation; called only through @ref io_service. 55   /// Destroy the implementation; called only through @ref io_service.
HITCBC 56   18311 virtual ~implementation() = default; 56   18114 virtual ~implementation() = default;
57   }; 57   };
58   58  
59   /** Constructs, closes, and destroys platform implementations on 59   /** Constructs, closes, and destroys platform implementations on
60   behalf of an I/O object. Platform backends implement this 60   behalf of an I/O object. Platform backends implement this
61   interface. 61   interface.
62   */ 62   */
63   struct BOOST_COROSIO_DECL io_service 63   struct BOOST_COROSIO_DECL io_service
64   { 64   {
65   /// Destroy the service; the execution context outlives it. 65   /// Destroy the service; the execution context outlives it.
HITCBC 66   4890 virtual ~io_service() = default; 66   4890 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* impl) = 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   15376 virtual void close([[maybe_unused]] handle& h) {} 75   15296 virtual void close([[maybe_unused]] handle& h) {}
76   }; 76   };
77   77  
78   /** Owns a platform-specific I/O implementation and destroys it 78   /** Owns a platform-specific I/O implementation and destroys it
79   when the handle goes out of scope. 79   when the handle goes out of scope.
80   */ 80   */
81   class handle 81   class handle
82   { 82   {
83   capy::execution_context* ctx_ = nullptr; 83   capy::execution_context* ctx_ = nullptr;
84   io_service* svc_ = nullptr; 84   io_service* svc_ = nullptr;
85   implementation* impl_ = nullptr; 85   implementation* impl_ = nullptr;
86   86  
87   public: 87   public:
88   /// Destroy the handle and its implementation. 88   /// Destroy the handle and its implementation.
HITCBC 89   55430 ~handle() 89   55120 ~handle()
90   { 90   {
HITCBC 91   55430 if (impl_) 91   55120 if (impl_)
92   { 92   {
HITCBC 93   27126 svc_->close(*this); 93   26971 svc_->close(*this);
HITCBC 94   27126 svc_->destroy(impl_); 94   26971 svc_->destroy(impl_);
95   } 95   }
HITCBC 96   55430 } 96   55120 }
97   97  
98   /// Construct an empty handle. 98   /// Construct an empty handle.
HITCBC 99   10 handle() = default; 99   10 handle() = default;
100   100  
101   /// Construct a handle bound to a context and service. 101   /// Construct a handle bound to a context and service.
HITCBC 102   27188 handle(capy::execution_context& ctx, io_service& svc) 102   27033 handle(capy::execution_context& ctx, io_service& svc)
HITCBC 103   27188 : ctx_(&ctx) 103   27033 : ctx_(&ctx)
HITCBC 104   27188 , svc_(&svc) 104   27033 , svc_(&svc)
HITCBC 105   27188 , impl_(svc_->construct()) 105   27033 , impl_(svc_->construct())
106   { 106   {
HITCBC 107   27188 } 107   27033 }
108   108  
109   /// Move construct from another handle. 109   /// Move construct from another handle.
HITCBC 110   28253 handle(handle&& other) noexcept 110   28098 handle(handle&& other) noexcept
HITCBC 111   28253 : ctx_(std::exchange(other.ctx_, nullptr)) 111   28098 : ctx_(std::exchange(other.ctx_, nullptr))
HITCBC 112   28253 , svc_(std::exchange(other.svc_, nullptr)) 112   28098 , svc_(std::exchange(other.svc_, nullptr))
HITCBC 113   28253 , impl_(std::exchange(other.impl_, nullptr)) 113   28098 , impl_(std::exchange(other.impl_, nullptr))
114   { 114   {
HITCBC 115   28253 } 115   28098 }
116   116  
117   /// Move assign from another handle. 117   /// Move assign from another handle.
HITCBC 118   42 handle& operator=(handle&& other) noexcept 118   42 handle& operator=(handle&& other) noexcept
119   { 119   {
HITCBC 120   42 if (this != &other) 120   42 if (this != &other)
121   { 121   {
HITCBC 122   42 if (impl_) 122   42 if (impl_)
123   { 123   {
HITCBC 124   41 svc_->close(*this); 124   41 svc_->close(*this);
HITCBC 125   41 svc_->destroy(impl_); 125   41 svc_->destroy(impl_);
126   } 126   }
HITCBC 127   42 ctx_ = std::exchange(other.ctx_, nullptr); 127   42 ctx_ = std::exchange(other.ctx_, nullptr);
HITCBC 128   42 svc_ = std::exchange(other.svc_, nullptr); 128   42 svc_ = std::exchange(other.svc_, nullptr);
HITCBC 129   42 impl_ = std::exchange(other.impl_, nullptr); 129   42 impl_ = std::exchange(other.impl_, nullptr);
130   } 130   }
HITCBC 131   42 return *this; 131   42 return *this;
132   } 132   }
133   133  
134   /// Copy construction is disabled; the implementation is uniquely owned. 134   /// Copy construction is disabled; the implementation is uniquely owned.
135   handle(handle const&) = delete; 135   handle(handle const&) = delete;
136   /// Copy assignment is disabled; the implementation is uniquely owned. 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   44886 explicit operator bool() const noexcept 140   44624 explicit operator bool() const noexcept
141   { 141   {
HITCBC 142   44886 return impl_ != nullptr; 142   44624 return impl_ != nullptr;
143   } 143   }
144   144  
145   /// Return the associated I/O service. 145   /// Return the associated I/O service.
HITCBC 146   19644 io_service& service() const noexcept 146   19532 io_service& service() const noexcept
147   { 147   {
HITCBC 148   19644 return *svc_; 148   19532 return *svc_;
149   } 149   }
150   150  
151   /// Return the platform implementation. 151   /// Return the platform implementation.
HITCBC 152   574501 implementation* get() const noexcept 152   597586 implementation* get() const noexcept
153   { 153   {
HITCBC 154   574501 return impl_; 154   597586 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   4657 void reset(implementation* p) noexcept 161   4619 void reset(implementation* p) noexcept
162   { 162   {
HITCBC 163   4657 if (impl_) 163   4619 if (impl_)
164   { 164   {
HITCBC 165   4657 svc_->close(*this); 165   4619 svc_->close(*this);
HITCBC 166   4657 svc_->destroy(impl_); 166   4619 svc_->destroy(impl_);
167   } 167   }
HITCBC 168   4657 impl_ = p; 168   4619 impl_ = p;
HITCBC 169   4657 } 169   4619 }
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   protected: 184   protected:
185   /// Destroy the object; protected, so only a derived type destroys one. 185   /// Destroy the object; protected, so only a derived type destroys one.
HITCBC 186   27909 virtual ~io_object() = default; 186   27754 virtual ~io_object() = default;
187   187  
188   /// Default construct for virtual base initialization. 188   /// Default construct for virtual base initialization.
HITCBC 189   10 io_object() noexcept = default; 189   10 io_object() noexcept = default;
190   190  
191   /** Create a handle bound to a service found in the context. 191   /** Create a handle bound to a service found in the context.
192   192  
193   @tparam Service The service type whose key_type is used for lookup. 193   @tparam Service The service type whose key_type is used for lookup.
194   @param ctx The execution context to search for the service. 194   @param ctx The execution context to search for the service.
195   195  
196   @return A handle owning a freshly constructed implementation. 196   @return A handle owning a freshly constructed implementation.
197   197  
198   @throws std::logic_error if the service is not installed. 198   @throws std::logic_error if the service is not installed.
199   */ 199   */
200   template<class Service> 200   template<class Service>
HITCBC 201   15129 static handle create_handle(capy::execution_context& ctx) 201   15049 static handle create_handle(capy::execution_context& ctx)
202   { 202   {
HITCBC 203   15129 auto* svc = ctx.find_service<Service>(); 203   15049 auto* svc = ctx.find_service<Service>();
HITCBC 204   15129 if (!svc) 204   15049 if (!svc)
HITCBC 205   4 detail::throw_logic_error( 205   4 detail::throw_logic_error(
206   "io_object::create_handle: service not installed"); 206   "io_object::create_handle: service not installed");
HITCBC 207   15125 return handle(ctx, *svc); 207   15045 return handle(ctx, *svc);
208   } 208   }
209   209  
210   /// Construct an I/O object from a handle. 210   /// Construct an I/O object from a handle.
HITCBC 211   27188 explicit io_object(handle h) noexcept : h_(std::move(h)) {} 211   27033 explicit io_object(handle h) noexcept : h_(std::move(h)) {}
212   212  
213   /// Move construct from another I/O object. 213   /// Move construct from another I/O object.
HITCBC 214   732 io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {} 214   732 io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
215   215  
216   /// Move assign from another I/O object. 216   /// Move assign from another I/O object.
HITCBC 217   4 io_object& operator=(io_object&& other) noexcept 217   4 io_object& operator=(io_object&& other) noexcept
218   { 218   {
HITCBC 219   4 if (this != &other) 219   4 if (this != &other)
HITCBC 220   4 h_ = std::move(other.h_); 220   4 h_ = std::move(other.h_);
HITCBC 221   4 return *this; 221   4 return *this;
222   } 222   }
223   223  
224   /// Copy construction is disabled; the handle is uniquely owned. 224   /// Copy construction is disabled; the handle is uniquely owned.
225   io_object(io_object const&) = delete; 225   io_object(io_object const&) = delete;
226   /// Copy assignment is disabled; the handle is uniquely owned. 226   /// Copy assignment is disabled; the handle is uniquely owned.
227   io_object& operator=(io_object const&) = delete; 227   io_object& operator=(io_object const&) = delete;
228   228  
229   /// The platform I/O handle owned by this object. 229   /// The platform I/O handle owned by this object.
230   BOOST_COROSIO_MSVC_WARNING_PUSH 230   BOOST_COROSIO_MSVC_WARNING_PUSH
231   BOOST_COROSIO_MSVC_WARNING_DISABLE(4251) 231   BOOST_COROSIO_MSVC_WARNING_DISABLE(4251)
232   handle h_; 232   handle h_;
233   BOOST_COROSIO_MSVC_WARNING_POP 233   BOOST_COROSIO_MSVC_WARNING_POP
234   }; 234   };
235   235  
236   } // namespace boost::corosio 236   } // namespace boost::corosio
237   237  
238   #endif 238   #endif