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   17569 virtual ~implementation() = default; 56   18115 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   5026 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   15077 virtual void close([[maybe_unused]] handle& h) {} 75   15337 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   54132 ~handle() 89   54848 ~handle()
90   { 90   {
HITCBC 91   54132 if (impl_) 91   54848 if (impl_)
92   { 92   {
HITCBC 93   26477 svc_->close(*this); 93   26835 svc_->close(*this);
HITCBC 94   26477 svc_->destroy(impl_); 94   26835 svc_->destroy(impl_);
95   } 95   }
HITCBC 96   54132 } 96   54848 }
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   26539 handle(capy::execution_context& ctx, io_service& svc) 102   26897 handle(capy::execution_context& ctx, io_service& svc)
HITCBC 103   26539 : ctx_(&ctx) 103   26897 : ctx_(&ctx)
HITCBC 104   26539 , svc_(&svc) 104   26897 , svc_(&svc)
HITCBC 105   26539 , impl_(svc_->construct()) 105   26897 , impl_(svc_->construct())
106   { 106   {
HITCBC 107   26539 } 107   26897 }
108   108  
109   /// Move construct from another handle. 109   /// Move construct from another handle.
HITCBC 110   27604 handle(handle&& other) noexcept 110   27962 handle(handle&& other) noexcept
HITCBC 111   27604 : ctx_(std::exchange(other.ctx_, nullptr)) 111   27962 : ctx_(std::exchange(other.ctx_, nullptr))
HITCBC 112   27604 , svc_(std::exchange(other.svc_, nullptr)) 112   27962 , svc_(std::exchange(other.svc_, nullptr))
HITCBC 113   27604 , impl_(std::exchange(other.impl_, nullptr)) 113   27962 , impl_(std::exchange(other.impl_, nullptr))
114   { 114   {
HITCBC 115   27604 } 115   27962 }
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   43664 explicit operator bool() const noexcept 140   43868 explicit operator bool() const noexcept
141   { 141   {
HITCBC 142   43664 return impl_ != nullptr; 142   43868 return impl_ != nullptr;
143   } 143   }
144   144  
145   /// Return the associated I/O service. 145   /// Return the associated I/O service.
HITCBC 146   19119 io_service& service() const noexcept 146   19273 io_service& service() const noexcept
147   { 147   {
HITCBC 148   19119 return *svc_; 148   19273 return *svc_;
149   } 149   }
150   150  
151   /// Return the platform implementation. 151   /// Return the platform implementation.
HITCBC 152   545899 implementation* get() const noexcept 152   544029 implementation* get() const noexcept
153   { 153   {
HITCBC 154   545899 return impl_; 154   544029 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   4482 void reset(implementation* p) noexcept 161   4496 void reset(implementation* p) noexcept
162   { 162   {
HITCBC 163   4482 if (impl_) 163   4496 if (impl_)
164   { 164   {
HITCBC 165   4482 svc_->close(*this); 165   4496 svc_->close(*this);
HITCBC 166   4482 svc_->destroy(impl_); 166   4496 svc_->destroy(impl_);
167   } 167   }
HITCBC 168   4482 impl_ = p; 168   4496 impl_ = p;
HITCBC 169   4482 } 169   4496 }
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   27260 virtual ~io_object() = default; 186   27618 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   14830 static handle create_handle(capy::execution_context& ctx) 201   15090 static handle create_handle(capy::execution_context& ctx)
202   { 202   {
HITCBC 203   14830 auto* svc = ctx.find_service<Service>(); 203   15090 auto* svc = ctx.find_service<Service>();
HITCBC 204   14830 if (!svc) 204   15090 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   14826 return handle(ctx, *svc); 207   15086 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   26539 explicit io_object(handle h) noexcept : h_(std::move(h)) {} 211   26897 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