win_iocp_overlapped_ptr.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. //
  2. // win_iocp_overlapped_ptr.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 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. #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
  11. #define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/push_options.hpp>
  16. #include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
  17. #if defined(BOOST_ASIO_HAS_IOCP)
  18. #include <boost/asio/detail/noncopyable.hpp>
  19. #include <boost/asio/detail/win_iocp_io_service.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace detail {
  23. // Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.
  24. class win_iocp_overlapped_ptr
  25. : private noncopyable
  26. {
  27. public:
  28. // Construct an empty win_iocp_overlapped_ptr.
  29. win_iocp_overlapped_ptr()
  30. : ptr_(0)
  31. {
  32. }
  33. // Construct an win_iocp_overlapped_ptr to contain the specified handler.
  34. template <typename Handler>
  35. explicit win_iocp_overlapped_ptr(
  36. boost::asio::io_service& io_service, Handler handler)
  37. : ptr_(0)
  38. {
  39. this->reset(io_service, handler);
  40. }
  41. // Destructor automatically frees the OVERLAPPED object unless released.
  42. ~win_iocp_overlapped_ptr()
  43. {
  44. reset();
  45. }
  46. // Reset to empty.
  47. void reset()
  48. {
  49. if (ptr_)
  50. {
  51. ptr_->destroy();
  52. ptr_ = 0;
  53. }
  54. }
  55. // Reset to contain the specified handler, freeing any current OVERLAPPED
  56. // object.
  57. template <typename Handler>
  58. void reset(boost::asio::io_service& io_service, Handler handler)
  59. {
  60. typedef overlapped_operation<Handler> value_type;
  61. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  62. raw_handler_ptr<alloc_traits> raw_ptr(handler);
  63. handler_ptr<alloc_traits> ptr(raw_ptr, io_service.impl_, handler);
  64. reset();
  65. ptr_ = ptr.release();
  66. }
  67. // Get the contained OVERLAPPED object.
  68. OVERLAPPED* get()
  69. {
  70. return ptr_;
  71. }
  72. // Get the contained OVERLAPPED object.
  73. const OVERLAPPED* get() const
  74. {
  75. return ptr_;
  76. }
  77. // Release ownership of the OVERLAPPED object.
  78. OVERLAPPED* release()
  79. {
  80. OVERLAPPED* tmp = ptr_;
  81. ptr_ = 0;
  82. return tmp;
  83. }
  84. // Post completion notification for overlapped operation. Releases ownership.
  85. void complete(const boost::system::error_code& ec,
  86. std::size_t bytes_transferred)
  87. {
  88. if (ptr_)
  89. {
  90. ptr_->ec_ = ec;
  91. ptr_->io_service_.post_completion(ptr_, 0,
  92. static_cast<DWORD>(bytes_transferred));
  93. ptr_ = 0;
  94. }
  95. }
  96. private:
  97. struct overlapped_operation_base
  98. : public win_iocp_io_service::operation
  99. {
  100. overlapped_operation_base(win_iocp_io_service& io_service,
  101. invoke_func_type invoke_func, destroy_func_type destroy_func)
  102. : win_iocp_io_service::operation(io_service, invoke_func, destroy_func),
  103. io_service_(io_service)
  104. {
  105. io_service_.work_started();
  106. }
  107. ~overlapped_operation_base()
  108. {
  109. io_service_.work_finished();
  110. }
  111. win_iocp_io_service& io_service_;
  112. boost::system::error_code ec_;
  113. };
  114. template <typename Handler>
  115. struct overlapped_operation
  116. : public overlapped_operation_base
  117. {
  118. overlapped_operation(win_iocp_io_service& io_service,
  119. Handler handler)
  120. : overlapped_operation_base(io_service,
  121. &overlapped_operation<Handler>::do_completion_impl,
  122. &overlapped_operation<Handler>::destroy_impl),
  123. handler_(handler)
  124. {
  125. }
  126. private:
  127. // Prevent copying and assignment.
  128. overlapped_operation(const overlapped_operation&);
  129. void operator=(const overlapped_operation&);
  130. static void do_completion_impl(win_iocp_io_service::operation* op,
  131. DWORD last_error, size_t bytes_transferred)
  132. {
  133. // Take ownership of the operation object.
  134. typedef overlapped_operation<Handler> op_type;
  135. op_type* handler_op(static_cast<op_type*>(op));
  136. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  137. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  138. // Make a copy of the handler and error_code so that the memory can be
  139. // deallocated before the upcall is made.
  140. Handler handler(handler_op->handler_);
  141. boost::system::error_code ec(handler_op->ec_);
  142. if (last_error)
  143. ec = boost::system::error_code(last_error,
  144. boost::asio::error::get_system_category());
  145. // Free the memory associated with the handler.
  146. ptr.reset();
  147. // Make the upcall.
  148. boost_asio_handler_invoke_helpers::invoke(
  149. bind_handler(handler, ec, bytes_transferred), &handler);
  150. }
  151. static void destroy_impl(win_iocp_io_service::operation* op)
  152. {
  153. // Take ownership of the operation object.
  154. typedef overlapped_operation<Handler> op_type;
  155. op_type* handler_op(static_cast<op_type*>(op));
  156. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  157. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  158. // A sub-object of the handler may be the true owner of the memory
  159. // associated with the handler. Consequently, a local copy of the handler
  160. // is required to ensure that any owning sub-object remains valid until
  161. // after we have deallocated the memory here.
  162. Handler handler(handler_op->handler_);
  163. (void)handler;
  164. // Free the memory associated with the handler.
  165. ptr.reset();
  166. }
  167. Handler handler_;
  168. };
  169. overlapped_operation_base* ptr_;
  170. };
  171. } // namespace detail
  172. } // namespace asio
  173. } // namespace boost
  174. #endif // defined(BOOST_ASIO_HAS_IOCP)
  175. #include <boost/asio/detail/pop_options.hpp>
  176. #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP