Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:46

0001 //
0002 // detail/win_iocp_handle_service.hpp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
0007 //
0008 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0009 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 //
0011 
0012 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
0013 #define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
0014 
0015 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0016 # pragma once
0017 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0018 
0019 #include <boost/asio/detail/config.hpp>
0020 
0021 #if defined(BOOST_ASIO_HAS_IOCP)
0022 
0023 #include <boost/asio/associated_cancellation_slot.hpp>
0024 #include <boost/asio/error.hpp>
0025 #include <boost/asio/execution_context.hpp>
0026 #include <boost/asio/detail/buffer_sequence_adapter.hpp>
0027 #include <boost/asio/detail/cstdint.hpp>
0028 #include <boost/asio/detail/handler_alloc_helpers.hpp>
0029 #include <boost/asio/detail/memory.hpp>
0030 #include <boost/asio/detail/mutex.hpp>
0031 #include <boost/asio/detail/operation.hpp>
0032 #include <boost/asio/detail/win_iocp_handle_read_op.hpp>
0033 #include <boost/asio/detail/win_iocp_handle_write_op.hpp>
0034 #include <boost/asio/detail/win_iocp_io_context.hpp>
0035 
0036 #include <boost/asio/detail/push_options.hpp>
0037 
0038 namespace boost {
0039 namespace asio {
0040 namespace detail {
0041 
0042 class win_iocp_handle_service :
0043   public execution_context_service_base<win_iocp_handle_service>
0044 {
0045 public:
0046   // The native type of a stream handle.
0047   typedef HANDLE native_handle_type;
0048 
0049   // The implementation type of the stream handle.
0050   class implementation_type
0051   {
0052   public:
0053     // Default constructor.
0054     implementation_type()
0055       : handle_(INVALID_HANDLE_VALUE),
0056         safe_cancellation_thread_id_(0),
0057         next_(0),
0058         prev_(0)
0059     {
0060     }
0061 
0062   private:
0063     // Only this service will have access to the internal values.
0064     friend class win_iocp_handle_service;
0065 
0066     // The native stream handle representation.
0067     native_handle_type handle_;
0068 
0069     // The ID of the thread from which it is safe to cancel asynchronous
0070     // operations. 0 means no asynchronous operations have been started yet.
0071     // ~0 means asynchronous operations have been started from more than one
0072     // thread, and cancellation is not supported for the handle.
0073     DWORD safe_cancellation_thread_id_;
0074 
0075     // Pointers to adjacent handle implementations in linked list.
0076     implementation_type* next_;
0077     implementation_type* prev_;
0078   };
0079 
0080   BOOST_ASIO_DECL win_iocp_handle_service(execution_context& context);
0081 
0082   // Destroy all user-defined handler objects owned by the service.
0083   BOOST_ASIO_DECL void shutdown();
0084 
0085   // Construct a new handle implementation.
0086   BOOST_ASIO_DECL void construct(implementation_type& impl);
0087 
0088   // Move-construct a new handle implementation.
0089   BOOST_ASIO_DECL void move_construct(implementation_type& impl,
0090       implementation_type& other_impl);
0091 
0092   // Move-assign from another handle implementation.
0093   BOOST_ASIO_DECL void move_assign(implementation_type& impl,
0094       win_iocp_handle_service& other_service,
0095       implementation_type& other_impl);
0096 
0097   // Destroy a handle implementation.
0098   BOOST_ASIO_DECL void destroy(implementation_type& impl);
0099 
0100   // Assign a native handle to a handle implementation.
0101   BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl,
0102       const native_handle_type& handle, boost::system::error_code& ec);
0103 
0104   // Determine whether the handle is open.
0105   bool is_open(const implementation_type& impl) const
0106   {
0107     return impl.handle_ != INVALID_HANDLE_VALUE;
0108   }
0109 
0110   // Destroy a handle implementation.
0111   BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl,
0112       boost::system::error_code& ec);
0113 
0114   // Release ownership of a handle.
0115   BOOST_ASIO_DECL native_handle_type release(implementation_type& impl,
0116       boost::system::error_code& ec);
0117 
0118   // Get the native handle representation.
0119   native_handle_type native_handle(const implementation_type& impl) const
0120   {
0121     return impl.handle_;
0122   }
0123 
0124   // Cancel all operations associated with the handle.
0125   BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl,
0126       boost::system::error_code& ec);
0127 
0128   // Write the given data. Returns the number of bytes written.
0129   template <typename ConstBufferSequence>
0130   size_t write_some(implementation_type& impl,
0131       const ConstBufferSequence& buffers, boost::system::error_code& ec)
0132   {
0133     return write_some_at(impl, 0, buffers, ec);
0134   }
0135 
0136   // Write the given data at the specified offset. Returns the number of bytes
0137   // written.
0138   template <typename ConstBufferSequence>
0139   size_t write_some_at(implementation_type& impl, uint64_t offset,
0140       const ConstBufferSequence& buffers, boost::system::error_code& ec)
0141   {
0142     boost::asio::const_buffer buffer =
0143       buffer_sequence_adapter<boost::asio::const_buffer,
0144         ConstBufferSequence>::first(buffers);
0145 
0146     return do_write(impl, offset, buffer, ec);
0147   }
0148 
0149   // Start an asynchronous write. The data being written must be valid for the
0150   // lifetime of the asynchronous operation.
0151   template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0152   void async_write_some(implementation_type& impl,
0153       const ConstBufferSequence& buffers,
0154       Handler& handler, const IoExecutor& io_ex)
0155   {
0156     associated_cancellation_slot_t<Handler> slot
0157       = boost::asio::get_associated_cancellation_slot(handler);
0158 
0159     // Allocate and construct an operation to wrap the handler.
0160     typedef win_iocp_handle_write_op<
0161         ConstBufferSequence, Handler, IoExecutor> op;
0162     typename op::ptr p = { boost::asio::detail::addressof(handler),
0163       op::ptr::allocate(handler), 0 };
0164     operation* o = p.p = new (p.v) op(buffers, handler, io_ex);
0165 
0166     BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
0167           reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some"));
0168 
0169     // Optionally register for per-operation cancellation.
0170     if (slot.is_connected())
0171       o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o);
0172 
0173     start_write_op(impl, 0,
0174         buffer_sequence_adapter<boost::asio::const_buffer,
0175           ConstBufferSequence>::first(buffers), o);
0176     p.v = p.p = 0;
0177   }
0178 
0179   // Start an asynchronous write at a specified offset. The data being written
0180   // must be valid for the lifetime of the asynchronous operation.
0181   template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
0182   void async_write_some_at(implementation_type& impl,
0183       uint64_t offset, const ConstBufferSequence& buffers,
0184       Handler& handler, const IoExecutor& io_ex)
0185   {
0186     associated_cancellation_slot_t<Handler> slot
0187       = boost::asio::get_associated_cancellation_slot(handler);
0188 
0189     // Allocate and construct an operation to wrap the handler.
0190     typedef win_iocp_handle_write_op<
0191         ConstBufferSequence, Handler, IoExecutor> op;
0192     typename op::ptr p = { boost::asio::detail::addressof(handler),
0193       op::ptr::allocate(handler), 0 };
0194     operation* o = p.p = new (p.v) op(buffers, handler, io_ex);
0195 
0196     BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
0197           reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at"));
0198 
0199     // Optionally register for per-operation cancellation.
0200     if (slot.is_connected())
0201       o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o);
0202 
0203     start_write_op(impl, offset,
0204         buffer_sequence_adapter<boost::asio::const_buffer,
0205           ConstBufferSequence>::first(buffers), o);
0206     p.v = p.p = 0;
0207   }
0208 
0209   // Read some data. Returns the number of bytes received.
0210   template <typename MutableBufferSequence>
0211   size_t read_some(implementation_type& impl,
0212       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0213   {
0214     return read_some_at(impl, 0, buffers, ec);
0215   }
0216 
0217   // Read some data at a specified offset. Returns the number of bytes received.
0218   template <typename MutableBufferSequence>
0219   size_t read_some_at(implementation_type& impl, uint64_t offset,
0220       const MutableBufferSequence& buffers, boost::system::error_code& ec)
0221   {
0222     boost::asio::mutable_buffer buffer =
0223       buffer_sequence_adapter<boost::asio::mutable_buffer,
0224         MutableBufferSequence>::first(buffers);
0225 
0226     return do_read(impl, offset, buffer, ec);
0227   }
0228 
0229   // Start an asynchronous read. The buffer for the data being received must be
0230   // valid for the lifetime of the asynchronous operation.
0231   template <typename MutableBufferSequence,
0232       typename Handler, typename IoExecutor>
0233   void async_read_some(implementation_type& impl,
0234       const MutableBufferSequence& buffers,
0235       Handler& handler, const IoExecutor& io_ex)
0236   {
0237     associated_cancellation_slot_t<Handler> slot
0238       = boost::asio::get_associated_cancellation_slot(handler);
0239 
0240     // Allocate and construct an operation to wrap the handler.
0241     typedef win_iocp_handle_read_op<
0242         MutableBufferSequence, Handler, IoExecutor> op;
0243     typename op::ptr p = { boost::asio::detail::addressof(handler),
0244       op::ptr::allocate(handler), 0 };
0245     operation* o = p.p = new (p.v) op(buffers, handler, io_ex);
0246 
0247     BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
0248           reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some"));
0249 
0250     // Optionally register for per-operation cancellation.
0251     if (slot.is_connected())
0252       o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o);
0253 
0254     start_read_op(impl, 0,
0255         buffer_sequence_adapter<boost::asio::mutable_buffer,
0256           MutableBufferSequence>::first(buffers), o);
0257     p.v = p.p = 0;
0258   }
0259 
0260   // Start an asynchronous read at a specified offset. The buffer for the data
0261   // being received must be valid for the lifetime of the asynchronous
0262   // operation.
0263   template <typename MutableBufferSequence,
0264       typename Handler, typename IoExecutor>
0265   void async_read_some_at(implementation_type& impl,
0266       uint64_t offset, const MutableBufferSequence& buffers,
0267       Handler& handler, const IoExecutor& io_ex)
0268   {
0269     associated_cancellation_slot_t<Handler> slot
0270       = boost::asio::get_associated_cancellation_slot(handler);
0271 
0272     // Allocate and construct an operation to wrap the handler.
0273     typedef win_iocp_handle_read_op<
0274         MutableBufferSequence, Handler, IoExecutor> op;
0275     typename op::ptr p = { boost::asio::detail::addressof(handler),
0276       op::ptr::allocate(handler), 0 };
0277     operation* o = p.p = new (p.v) op(buffers, handler, io_ex);
0278 
0279     BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
0280           reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at"));
0281 
0282     // Optionally register for per-operation cancellation.
0283     if (slot.is_connected())
0284       o = &slot.template emplace<iocp_op_cancellation>(impl.handle_, o);
0285 
0286     start_read_op(impl, offset,
0287         buffer_sequence_adapter<boost::asio::mutable_buffer,
0288           MutableBufferSequence>::first(buffers), o);
0289     p.v = p.p = 0;
0290   }
0291 
0292 private:
0293   // Prevent the use of the null_buffers type with this service.
0294   size_t write_some(implementation_type& impl,
0295       const null_buffers& buffers, boost::system::error_code& ec);
0296   size_t write_some_at(implementation_type& impl, uint64_t offset,
0297       const null_buffers& buffers, boost::system::error_code& ec);
0298   template <typename Handler, typename IoExecutor>
0299   void async_write_some(implementation_type& impl,
0300       const null_buffers& buffers, Handler& handler,
0301       const IoExecutor& io_ex);
0302   template <typename Handler, typename IoExecutor>
0303   void async_write_some_at(implementation_type& impl, uint64_t offset,
0304       const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
0305   size_t read_some(implementation_type& impl,
0306       const null_buffers& buffers, boost::system::error_code& ec);
0307   size_t read_some_at(implementation_type& impl, uint64_t offset,
0308       const null_buffers& buffers, boost::system::error_code& ec);
0309   template <typename Handler, typename IoExecutor>
0310   void async_read_some(implementation_type& impl,
0311       const null_buffers& buffers, Handler& handler,
0312       const IoExecutor& io_ex);
0313   template <typename Handler, typename IoExecutor>
0314   void async_read_some_at(implementation_type& impl, uint64_t offset,
0315       const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex);
0316 
0317   // Helper class for waiting for synchronous operations to complete.
0318   class overlapped_wrapper;
0319 
0320   // Helper function to perform a synchronous write operation.
0321   BOOST_ASIO_DECL size_t do_write(implementation_type& impl,
0322       uint64_t offset, const boost::asio::const_buffer& buffer,
0323       boost::system::error_code& ec);
0324 
0325   // Helper function to start a write operation.
0326   BOOST_ASIO_DECL void start_write_op(implementation_type& impl,
0327       uint64_t offset, const boost::asio::const_buffer& buffer,
0328       operation* op);
0329 
0330   // Helper function to perform a synchronous write operation.
0331   BOOST_ASIO_DECL size_t do_read(implementation_type& impl,
0332       uint64_t offset, const boost::asio::mutable_buffer& buffer,
0333       boost::system::error_code& ec);
0334 
0335   // Helper function to start a read operation.
0336   BOOST_ASIO_DECL void start_read_op(implementation_type& impl,
0337       uint64_t offset, const boost::asio::mutable_buffer& buffer,
0338       operation* op);
0339 
0340   // Update the ID of the thread from which cancellation is safe.
0341   BOOST_ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);
0342 
0343   // Helper function to close a handle when the associated object is being
0344   // destroyed.
0345   BOOST_ASIO_DECL void close_for_destruction(implementation_type& impl);
0346 
0347   // The type of a NtSetInformationFile function pointer.
0348   typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG);
0349 
0350   // Helper function to get the NtSetInformationFile function pointer. If no
0351   // NtSetInformationFile pointer has been obtained yet, one is obtained using
0352   // GetProcAddress and the pointer is cached. Returns a null pointer if
0353   // NtSetInformationFile is not available.
0354   BOOST_ASIO_DECL nt_set_info_fn get_nt_set_info();
0355 
0356   // Helper function to emulate InterlockedCompareExchangePointer functionality
0357   // for:
0358   // - very old Platform SDKs; and
0359   // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
0360   BOOST_ASIO_DECL void* interlocked_compare_exchange_pointer(
0361       void** dest, void* exch, void* cmp);
0362 
0363   // Helper function to emulate InterlockedExchangePointer functionality for:
0364   // - very old Platform SDKs; and
0365   // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
0366   BOOST_ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
0367 
0368   // Helper class used to implement per operation cancellation.
0369   class iocp_op_cancellation : public operation
0370   {
0371   public:
0372     iocp_op_cancellation(HANDLE h, operation* target)
0373       : operation(&iocp_op_cancellation::do_complete),
0374         handle_(h),
0375         target_(target)
0376     {
0377     }
0378 
0379     static void do_complete(void* owner, operation* base,
0380         const boost::system::error_code& result_ec,
0381         std::size_t bytes_transferred)
0382     {
0383       iocp_op_cancellation* o = static_cast<iocp_op_cancellation*>(base);
0384       o->target_->complete(owner, result_ec, bytes_transferred);
0385     }
0386 
0387     void operator()(cancellation_type_t type)
0388     {
0389 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
0390       if (!!(type &
0391             (cancellation_type::terminal
0392               | cancellation_type::partial
0393               | cancellation_type::total)))
0394       {
0395         ::CancelIoEx(handle_, this);
0396       }
0397 #else // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
0398       (void)type;
0399 #endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
0400     }
0401 
0402   private:
0403     HANDLE handle_;
0404     operation* target_;
0405   };
0406 
0407   // The IOCP service used for running asynchronous operations and dispatching
0408   // handlers.
0409   win_iocp_io_context& iocp_service_;
0410 
0411   // Pointer to NtSetInformationFile implementation.
0412   void* nt_set_info_;
0413 
0414   // Mutex to protect access to the linked list of implementations.
0415   mutex mutex_;
0416 
0417   // The head of a linked list of all implementations.
0418   implementation_type* impl_list_;
0419 };
0420 
0421 } // namespace detail
0422 } // namespace asio
0423 } // namespace boost
0424 
0425 #include <boost/asio/detail/pop_options.hpp>
0426 
0427 #if defined(BOOST_ASIO_HEADER_ONLY)
0428 # include <boost/asio/detail/impl/win_iocp_handle_service.ipp>
0429 #endif // defined(BOOST_ASIO_HEADER_ONLY)
0430 
0431 #endif // defined(BOOST_ASIO_HAS_IOCP)
0432 
0433 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP