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   17455 virtual ~implementation() = default; 56   17607 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   24651 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   15233 virtual void close([[maybe_unused]] handle& h) {} 75   15136 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   54234 ~handle() 89   53996 ~handle()
90   { 90   {
HITCBC 91   54234 if (impl_) 91   53996 if (impl_)
92   { 92   {
HITCBC 93   26525 svc_->close(*this); 93   26409 svc_->close(*this);
HITCBC 94   26525 svc_->destroy(impl_); 94   26409 svc_->destroy(impl_);
95   } 95   }
HITCBC 96   54234 } 96   53996 }
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   26587 handle(capy::execution_context& ctx, io_service& svc) 102   26471 handle(capy::execution_context& ctx, io_service& svc)
HITCBC 103   26587 : ctx_(&ctx) 103   26471 : ctx_(&ctx)
HITCBC 104   26587 , svc_(&svc) 104   26471 , svc_(&svc)
HITCBC 105   26587 , impl_(svc_->construct()) 105   26471 , impl_(svc_->construct())
106   { 106   {
HITCBC 107   26587 } 107   26471 }
108   108  
109   /// Move construct from another handle. 109   /// Move construct from another handle.
HITCBC 110   27658 handle(handle&& other) noexcept 110   27536 handle(handle&& other) noexcept
HITCBC 111   27658 : ctx_(std::exchange(other.ctx_, nullptr)) 111   27536 : ctx_(std::exchange(other.ctx_, nullptr))
HITCBC 112   27658 , svc_(std::exchange(other.svc_, nullptr)) 112   27536 , svc_(std::exchange(other.svc_, nullptr))
HITCBC 113   27658 , impl_(std::exchange(other.impl_, nullptr)) 113   27536 , impl_(std::exchange(other.impl_, nullptr))
114   { 114   {
HITCBC 115   27658 } 115   27536 }
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   43381 explicit operator bool() const noexcept 140   43219 explicit operator bool() const noexcept
141   { 141   {
HITCBC 142   43381 return impl_ != nullptr; 142   43219 return impl_ != nullptr;
143   } 143   }
144   144  
145   /// Return the associated I/O service. 145   /// Return the associated I/O service.
HITCBC 146   19017 io_service& service() const noexcept 146   18929 io_service& service() const noexcept
147   { 147   {
HITCBC 148   19017 return *svc_; 148   18929 return *svc_;
149   } 149   }
150   150  
151   /// Return the platform implementation. 151   /// Return the platform implementation.
HITCBC 152   575077 implementation* get() const noexcept 152   556393 implementation* get() const noexcept
153   { 153   {
HITCBC 154   575077 return impl_; 154   556393 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   4440 void reset(implementation* p) noexcept 161   4418 void reset(implementation* p) noexcept
162   { 162   {
HITCBC 163   4440 if (impl_) 163   4418 if (impl_)
164   { 164   {
HITCBC 165   4440 svc_->close(*this); 165   4418 svc_->close(*this);
HITCBC 166   4440 svc_->destroy(impl_); 166   4418 svc_->destroy(impl_);
167   } 167   }
HITCBC 168   4440 impl_ = p; 168   4418 impl_ = p;
HITCBC 169   4440 } 169   4418 }
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   27316 virtual ~io_object() = default; 186   27192 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   26591 static handle create_handle(capy::execution_context& ctx) 201   14889 static handle create_handle(capy::execution_context& ctx)
202   { 202   {
HITCBC 203   26591 auto* svc = ctx.find_service<Service>(); 203   14889 auto* svc = ctx.find_service<Service>();
HITCBC 204   26591 if (!svc) 204   14889 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   26587 return handle(ctx, *svc); 207   14885 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   26587 explicit io_object(handle h) noexcept : h_(std::move(h)) {} 211   26471 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   740 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