1 // 2 // detail/win_iocp_handle_service.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // Copyright (c) 2008 Rep Invariant Systems, Inc. ([email protected]) 7 // 8 // Distributed under the Boost Software License, Version 1.0. (See accompanying 9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 // 11 12 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP 13 #define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP 14 15 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 16 # pragma once 17 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 18 19 #include <boost/asio/detail/config.hpp> 20 21 #if defined(BOOST_ASIO_HAS_IOCP) 22 23 #include <boost/asio/error.hpp> 24 #include <boost/asio/execution_context.hpp> 25 #include <boost/asio/detail/buffer_sequence_adapter.hpp> 26 #include <boost/asio/detail/cstdint.hpp> 27 #include <boost/asio/detail/handler_alloc_helpers.hpp> 28 #include <boost/asio/detail/memory.hpp> 29 #include <boost/asio/detail/mutex.hpp> 30 #include <boost/asio/detail/operation.hpp> 31 #include <boost/asio/detail/win_iocp_handle_read_op.hpp> 32 #include <boost/asio/detail/win_iocp_handle_write_op.hpp> 33 #include <boost/asio/detail/win_iocp_io_context.hpp> 34 35 #include <boost/asio/detail/push_options.hpp> 36 37 namespace boost { 38 namespace asio { 39 namespace detail { 40 41 class win_iocp_handle_service : 42 public execution_context_service_base<win_iocp_handle_service> 43 { 44 public: 45 // The native type of a stream handle. 46 typedef HANDLE native_handle_type; 47 48 // The implementation type of the stream handle. 49 class implementation_type 50 { 51 public: 52 // Default constructor. implementation_type()53 implementation_type() 54 : handle_(INVALID_HANDLE_VALUE), 55 safe_cancellation_thread_id_(0), 56 next_(0), 57 prev_(0) 58 { 59 } 60 61 private: 62 // Only this service will have access to the internal values. 63 friend class win_iocp_handle_service; 64 65 // The native stream handle representation. 66 native_handle_type handle_; 67 68 // The ID of the thread from which it is safe to cancel asynchronous 69 // operations. 0 means no asynchronous operations have been started yet. 70 // ~0 means asynchronous operations have been started from more than one 71 // thread, and cancellation is not supported for the handle. 72 DWORD safe_cancellation_thread_id_; 73 74 // Pointers to adjacent handle implementations in linked list. 75 implementation_type* next_; 76 implementation_type* prev_; 77 }; 78 79 BOOST_ASIO_DECL win_iocp_handle_service(execution_context& context); 80 81 // Destroy all user-defined handler objects owned by the service. 82 BOOST_ASIO_DECL void shutdown(); 83 84 // Construct a new handle implementation. 85 BOOST_ASIO_DECL void construct(implementation_type& impl); 86 87 // Move-construct a new handle implementation. 88 BOOST_ASIO_DECL void move_construct(implementation_type& impl, 89 implementation_type& other_impl); 90 91 // Move-assign from another handle implementation. 92 BOOST_ASIO_DECL void move_assign(implementation_type& impl, 93 win_iocp_handle_service& other_service, 94 implementation_type& other_impl); 95 96 // Destroy a handle implementation. 97 BOOST_ASIO_DECL void destroy(implementation_type& impl); 98 99 // Assign a native handle to a handle implementation. 100 BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, 101 const native_handle_type& handle, boost::system::error_code& ec); 102 103 // Determine whether the handle is open. is_open(const implementation_type & impl) const104 bool is_open(const implementation_type& impl) const 105 { 106 return impl.handle_ != INVALID_HANDLE_VALUE; 107 } 108 109 // Destroy a handle implementation. 110 BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, 111 boost::system::error_code& ec); 112 113 // Get the native handle representation. native_handle(const implementation_type & impl) const114 native_handle_type native_handle(const implementation_type& impl) const 115 { 116 return impl.handle_; 117 } 118 119 // Cancel all operations associated with the handle. 120 BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, 121 boost::system::error_code& ec); 122 123 // Write the given data. Returns the number of bytes written. 124 template <typename ConstBufferSequence> write_some(implementation_type & impl,const ConstBufferSequence & buffers,boost::system::error_code & ec)125 size_t write_some(implementation_type& impl, 126 const ConstBufferSequence& buffers, boost::system::error_code& ec) 127 { 128 return write_some_at(impl, 0, buffers, ec); 129 } 130 131 // Write the given data at the specified offset. Returns the number of bytes 132 // written. 133 template <typename ConstBufferSequence> write_some_at(implementation_type & impl,uint64_t offset,const ConstBufferSequence & buffers,boost::system::error_code & ec)134 size_t write_some_at(implementation_type& impl, uint64_t offset, 135 const ConstBufferSequence& buffers, boost::system::error_code& ec) 136 { 137 boost::asio::const_buffer buffer = 138 buffer_sequence_adapter<boost::asio::const_buffer, 139 ConstBufferSequence>::first(buffers); 140 141 return do_write(impl, offset, buffer, ec); 142 } 143 144 // Start an asynchronous write. The data being written must be valid for the 145 // lifetime of the asynchronous operation. 146 template <typename ConstBufferSequence, typename Handler, typename IoExecutor> async_write_some(implementation_type & impl,const ConstBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)147 void async_write_some(implementation_type& impl, 148 const ConstBufferSequence& buffers, 149 Handler& handler, const IoExecutor& io_ex) 150 { 151 // Allocate and construct an operation to wrap the handler. 152 typedef win_iocp_handle_write_op< 153 ConstBufferSequence, Handler, IoExecutor> op; 154 typename op::ptr p = { boost::asio::detail::addressof(handler), 155 op::ptr::allocate(handler), 0 }; 156 p.p = new (p.v) op(buffers, handler, io_ex); 157 158 BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, 159 reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some")); 160 161 start_write_op(impl, 0, 162 buffer_sequence_adapter<boost::asio::const_buffer, 163 ConstBufferSequence>::first(buffers), p.p); 164 p.v = p.p = 0; 165 } 166 167 // Start an asynchronous write at a specified offset. The data being written 168 // must be valid for the lifetime of the asynchronous operation. 169 template <typename ConstBufferSequence, typename Handler, typename IoExecutor> async_write_some_at(implementation_type & impl,uint64_t offset,const ConstBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)170 void async_write_some_at(implementation_type& impl, 171 uint64_t offset, const ConstBufferSequence& buffers, 172 Handler& handler, const IoExecutor& io_ex) 173 { 174 // Allocate and construct an operation to wrap the handler. 175 typedef win_iocp_handle_write_op< 176 ConstBufferSequence, Handler, IoExecutor> op; 177 typename op::ptr p = { boost::asio::detail::addressof(handler), 178 op::ptr::allocate(handler), 0 }; 179 p.p = new (p.v) op(buffers, handler, io_ex); 180 181 BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, 182 reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at")); 183 184 start_write_op(impl, offset, 185 buffer_sequence_adapter<boost::asio::const_buffer, 186 ConstBufferSequence>::first(buffers), p.p); 187 p.v = p.p = 0; 188 } 189 190 // Read some data. Returns the number of bytes received. 191 template <typename MutableBufferSequence> read_some(implementation_type & impl,const MutableBufferSequence & buffers,boost::system::error_code & ec)192 size_t read_some(implementation_type& impl, 193 const MutableBufferSequence& buffers, boost::system::error_code& ec) 194 { 195 return read_some_at(impl, 0, buffers, ec); 196 } 197 198 // Read some data at a specified offset. Returns the number of bytes received. 199 template <typename MutableBufferSequence> read_some_at(implementation_type & impl,uint64_t offset,const MutableBufferSequence & buffers,boost::system::error_code & ec)200 size_t read_some_at(implementation_type& impl, uint64_t offset, 201 const MutableBufferSequence& buffers, boost::system::error_code& ec) 202 { 203 boost::asio::mutable_buffer buffer = 204 buffer_sequence_adapter<boost::asio::mutable_buffer, 205 MutableBufferSequence>::first(buffers); 206 207 return do_read(impl, offset, buffer, ec); 208 } 209 210 // Start an asynchronous read. The buffer for the data being received must be 211 // valid for the lifetime of the asynchronous operation. 212 template <typename MutableBufferSequence, 213 typename Handler, typename IoExecutor> async_read_some(implementation_type & impl,const MutableBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)214 void async_read_some(implementation_type& impl, 215 const MutableBufferSequence& buffers, 216 Handler& handler, const IoExecutor& io_ex) 217 { 218 // Allocate and construct an operation to wrap the handler. 219 typedef win_iocp_handle_read_op< 220 MutableBufferSequence, Handler, IoExecutor> op; 221 typename op::ptr p = { boost::asio::detail::addressof(handler), 222 op::ptr::allocate(handler), 0 }; 223 p.p = new (p.v) op(buffers, handler, io_ex); 224 225 BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, 226 reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some")); 227 228 start_read_op(impl, 0, 229 buffer_sequence_adapter<boost::asio::mutable_buffer, 230 MutableBufferSequence>::first(buffers), p.p); 231 p.v = p.p = 0; 232 } 233 234 // Start an asynchronous read at a specified offset. The buffer for the data 235 // being received must be valid for the lifetime of the asynchronous 236 // operation. 237 template <typename MutableBufferSequence, 238 typename Handler, typename IoExecutor> async_read_some_at(implementation_type & impl,uint64_t offset,const MutableBufferSequence & buffers,Handler & handler,const IoExecutor & io_ex)239 void async_read_some_at(implementation_type& impl, 240 uint64_t offset, const MutableBufferSequence& buffers, 241 Handler& handler, const IoExecutor& io_ex) 242 { 243 // Allocate and construct an operation to wrap the handler. 244 typedef win_iocp_handle_read_op< 245 MutableBufferSequence, Handler, IoExecutor> op; 246 typename op::ptr p = { boost::asio::detail::addressof(handler), 247 op::ptr::allocate(handler), 0 }; 248 p.p = new (p.v) op(buffers, handler, io_ex); 249 250 BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, 251 reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at")); 252 253 start_read_op(impl, offset, 254 buffer_sequence_adapter<boost::asio::mutable_buffer, 255 MutableBufferSequence>::first(buffers), p.p); 256 p.v = p.p = 0; 257 } 258 259 private: 260 // Prevent the use of the null_buffers type with this service. 261 size_t write_some(implementation_type& impl, 262 const null_buffers& buffers, boost::system::error_code& ec); 263 size_t write_some_at(implementation_type& impl, uint64_t offset, 264 const null_buffers& buffers, boost::system::error_code& ec); 265 template <typename Handler, typename IoExecutor> 266 void async_write_some(implementation_type& impl, 267 const null_buffers& buffers, Handler& handler, 268 const IoExecutor& io_ex); 269 template <typename Handler, typename IoExecutor> 270 void async_write_some_at(implementation_type& impl, uint64_t offset, 271 const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); 272 size_t read_some(implementation_type& impl, 273 const null_buffers& buffers, boost::system::error_code& ec); 274 size_t read_some_at(implementation_type& impl, uint64_t offset, 275 const null_buffers& buffers, boost::system::error_code& ec); 276 template <typename Handler, typename IoExecutor> 277 void async_read_some(implementation_type& impl, 278 const null_buffers& buffers, Handler& handler, 279 const IoExecutor& io_ex); 280 template <typename Handler, typename IoExecutor> 281 void async_read_some_at(implementation_type& impl, uint64_t offset, 282 const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); 283 284 // Helper class for waiting for synchronous operations to complete. 285 class overlapped_wrapper; 286 287 // Helper function to perform a synchronous write operation. 288 BOOST_ASIO_DECL size_t do_write(implementation_type& impl, 289 uint64_t offset, const boost::asio::const_buffer& buffer, 290 boost::system::error_code& ec); 291 292 // Helper function to start a write operation. 293 BOOST_ASIO_DECL void start_write_op(implementation_type& impl, 294 uint64_t offset, const boost::asio::const_buffer& buffer, 295 operation* op); 296 297 // Helper function to perform a synchronous write operation. 298 BOOST_ASIO_DECL size_t do_read(implementation_type& impl, 299 uint64_t offset, const boost::asio::mutable_buffer& buffer, 300 boost::system::error_code& ec); 301 302 // Helper function to start a read operation. 303 BOOST_ASIO_DECL void start_read_op(implementation_type& impl, 304 uint64_t offset, const boost::asio::mutable_buffer& buffer, 305 operation* op); 306 307 // Update the ID of the thread from which cancellation is safe. 308 BOOST_ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); 309 310 // Helper function to close a handle when the associated object is being 311 // destroyed. 312 BOOST_ASIO_DECL void close_for_destruction(implementation_type& impl); 313 314 // The IOCP service used for running asynchronous operations and dispatching 315 // handlers. 316 win_iocp_io_context& iocp_service_; 317 318 // Mutex to protect access to the linked list of implementations. 319 mutex mutex_; 320 321 // The head of a linked list of all implementations. 322 implementation_type* impl_list_; 323 }; 324 325 } // namespace detail 326 } // namespace asio 327 } // namespace boost 328 329 #include <boost/asio/detail/pop_options.hpp> 330 331 #if defined(BOOST_ASIO_HEADER_ONLY) 332 # include <boost/asio/detail/impl/win_iocp_handle_service.ipp> 333 #endif // defined(BOOST_ASIO_HEADER_ONLY) 334 335 #endif // defined(BOOST_ASIO_HAS_IOCP) 336 337 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP 338