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   18255 virtual ~implementation() = default; 56   17982 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   15336 virtual void close([[maybe_unused]] handle& h) {} 75   15232 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   55276 ~handle() 89   54844 ~handle()
90   { 90   {
HITCBC 91   55276 if (impl_) 91   54844 if (impl_)
92   { 92   {
HITCBC 93   27049 svc_->close(*this); 93   26833 svc_->close(*this);
HITCBC 94   27049 svc_->destroy(impl_); 94   26833 svc_->destroy(impl_);
95   } 95   }
HITCBC 96   55276 } 96   54844 }
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   27111 handle(capy::execution_context& ctx, io_service& svc) 102   26895 handle(capy::execution_context& ctx, io_service& svc)
HITCBC 103   27111 : ctx_(&ctx) 103   26895 : ctx_(&ctx)
HITCBC 104   27111 , svc_(&svc) 104   26895 , svc_(&svc)
HITCBC 105   27111 , impl_(svc_->construct()) 105   26895 , impl_(svc_->construct())
106   { 106   {
HITCBC 107   27111 } 107   26895 }
108   108  
109   /// Move construct from another handle. 109   /// Move construct from another handle.
HITCBC 110   28176 handle(handle&& other) noexcept 110   27960 handle(handle&& other) noexcept
HITCBC 111   28176 : ctx_(std::exchange(other.ctx_, nullptr)) 111   27960 : ctx_(std::exchange(other.ctx_, nullptr))
HITCBC 112   28176 , svc_(std::exchange(other.svc_, nullptr)) 112   27960 , svc_(std::exchange(other.svc_, nullptr))
HITCBC 113   28176 , impl_(std::exchange(other.impl_, nullptr)) 113   27960 , impl_(std::exchange(other.impl_, nullptr))
114   { 114   {
HITCBC 115   28176 } 115   27960 }
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   44756 explicit operator bool() const noexcept 140   44364 explicit operator bool() const noexcept
141   { 141   {
HITCBC 142   44756 return impl_ != nullptr; 142   44364 return impl_ != nullptr;
143   } 143   }
144   144  
145   /// Return the associated I/O service. 145   /// Return the associated I/O service.
HITCBC 146   19588 io_service& service() const noexcept 146   19421 io_service& service() const noexcept
147   { 147   {
HITCBC 148   19588 return *svc_; 148   19421 return *svc_;
149   } 149   }
150   150  
151   /// Return the platform implementation. 151   /// Return the platform implementation.
HITCBC 152   586715 implementation* get() const noexcept 152   551079 implementation* get() const noexcept
153   { 153   {
HITCBC 154   586715 return impl_; 154   551079 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   4639 void reset(implementation* p) noexcept 161   4582 void reset(implementation* p) noexcept
162   { 162   {
HITCBC 163   4639 if (impl_) 163   4582 if (impl_)
164   { 164   {
HITCBC 165   4639 svc_->close(*this); 165   4582 svc_->close(*this);
HITCBC 166   4639 svc_->destroy(impl_); 166   4582 svc_->destroy(impl_);
167   } 167   }
HITCBC 168   4639 impl_ = p; 168   4582 impl_ = p;
HITCBC 169   4639 } 169   4582 }
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   27832 virtual ~io_object() = default; 186   27616 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   15089 static handle create_handle(capy::execution_context& ctx) 201   14985 static handle create_handle(capy::execution_context& ctx)
202   { 202   {
HITCBC 203   15089 auto* svc = ctx.find_service<Service>(); 203   14985 auto* svc = ctx.find_service<Service>();
HITCBC 204   15089 if (!svc) 204   14985 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   15085 return handle(ctx, *svc); 207   14981 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   27111 explicit io_object(handle h) noexcept : h_(std::move(h)) {} 211   26895 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