1 // 2 // detail/win_iocp_overlapped_ptr.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP 12 #define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 20 #if defined(BOOST_ASIO_HAS_IOCP) 21 22 #include <boost/asio/io_context.hpp> 23 #include <boost/asio/query.hpp> 24 #include <boost/asio/detail/handler_alloc_helpers.hpp> 25 #include <boost/asio/detail/memory.hpp> 26 #include <boost/asio/detail/noncopyable.hpp> 27 #include <boost/asio/detail/win_iocp_overlapped_op.hpp> 28 #include <boost/asio/detail/win_iocp_io_context.hpp> 29 30 #include <boost/asio/detail/push_options.hpp> 31 32 namespace boost { 33 namespace asio { 34 namespace detail { 35 36 // Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. 37 class win_iocp_overlapped_ptr 38 : private noncopyable 39 { 40 public: 41 // Construct an empty win_iocp_overlapped_ptr. win_iocp_overlapped_ptr()42 win_iocp_overlapped_ptr() 43 : ptr_(0), 44 iocp_service_(0) 45 { 46 } 47 48 // Construct an win_iocp_overlapped_ptr to contain the specified handler. 49 template <typename Executor, typename Handler> win_iocp_overlapped_ptr(const Executor & ex,BOOST_ASIO_MOVE_ARG (Handler)handler)50 explicit win_iocp_overlapped_ptr(const Executor& ex, 51 BOOST_ASIO_MOVE_ARG(Handler) handler) 52 : ptr_(0), 53 iocp_service_(0) 54 { 55 this->reset(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)); 56 } 57 58 // Destructor automatically frees the OVERLAPPED object unless released. ~win_iocp_overlapped_ptr()59 ~win_iocp_overlapped_ptr() 60 { 61 reset(); 62 } 63 64 // Reset to empty. reset()65 void reset() 66 { 67 if (ptr_) 68 { 69 ptr_->destroy(); 70 ptr_ = 0; 71 iocp_service_->work_finished(); 72 iocp_service_ = 0; 73 } 74 } 75 76 // Reset to contain the specified handler, freeing any current OVERLAPPED 77 // object. 78 template <typename Executor, typename Handler> reset(const Executor & ex,Handler handler)79 void reset(const Executor& ex, Handler handler) 80 { 81 win_iocp_io_context* iocp_service = this->get_iocp_service(ex); 82 83 typedef win_iocp_overlapped_op<Handler, Executor> op; 84 typename op::ptr p = { boost::asio::detail::addressof(handler), 85 op::ptr::allocate(handler), 0 }; 86 p.p = new (p.v) op(handler, ex); 87 88 BOOST_ASIO_HANDLER_CREATION((ex.context(), *p.p, 89 "iocp_service", iocp_service, 0, "overlapped")); 90 91 iocp_service->work_started(); 92 reset(); 93 ptr_ = p.p; 94 p.v = p.p = 0; 95 iocp_service_ = iocp_service; 96 } 97 98 // Get the contained OVERLAPPED object. get()99 OVERLAPPED* get() 100 { 101 return ptr_; 102 } 103 104 // Get the contained OVERLAPPED object. get() const105 const OVERLAPPED* get() const 106 { 107 return ptr_; 108 } 109 110 // Release ownership of the OVERLAPPED object. release()111 OVERLAPPED* release() 112 { 113 if (ptr_) 114 iocp_service_->on_pending(ptr_); 115 116 OVERLAPPED* tmp = ptr_; 117 ptr_ = 0; 118 iocp_service_ = 0; 119 return tmp; 120 } 121 122 // Post completion notification for overlapped operation. Releases ownership. complete(const boost::system::error_code & ec,std::size_t bytes_transferred)123 void complete(const boost::system::error_code& ec, 124 std::size_t bytes_transferred) 125 { 126 if (ptr_) 127 { 128 iocp_service_->on_completion(ptr_, ec, 129 static_cast<DWORD>(bytes_transferred)); 130 ptr_ = 0; 131 iocp_service_ = 0; 132 } 133 } 134 135 private: 136 template <typename Executor> get_iocp_service(const Executor & ex,typename enable_if<can_query<const Executor &,execution::context_t>::value>::type * =0)137 static win_iocp_io_context* get_iocp_service(const Executor& ex, 138 typename enable_if< 139 can_query<const Executor&, execution::context_t>::value 140 >::type* = 0) 141 { 142 return &use_service<win_iocp_io_context>( 143 boost::asio::query(ex, execution::context)); 144 } 145 146 template <typename Executor> get_iocp_service(const Executor & ex,typename enable_if<!can_query<const Executor &,execution::context_t>::value>::type * =0)147 static win_iocp_io_context* get_iocp_service(const Executor& ex, 148 typename enable_if< 149 !can_query<const Executor&, execution::context_t>::value 150 >::type* = 0) 151 { 152 return &use_service<win_iocp_io_context>(ex.context()); 153 } 154 get_iocp_service(const io_context::executor_type & ex)155 static win_iocp_io_context* get_iocp_service( 156 const io_context::executor_type& ex) 157 { 158 return &boost::asio::query(ex, execution::context).impl_; 159 } 160 161 win_iocp_operation* ptr_; 162 win_iocp_io_context* iocp_service_; 163 }; 164 165 } // namespace detail 166 } // namespace asio 167 } // namespace boost 168 169 #include <boost/asio/detail/pop_options.hpp> 170 171 #endif // defined(BOOST_ASIO_HAS_IOCP) 172 173 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP 174