win_iocp_handle_service.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. //
  2. // win_iocp_handle_service.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
  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. #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
  12. #define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
  18. #if defined(BOOST_ASIO_HAS_IOCP)
  19. #include <boost/asio/detail/push_options.hpp>
  20. #include <boost/cstdint.hpp>
  21. #include <boost/asio/detail/pop_options.hpp>
  22. #include <boost/asio/buffer.hpp>
  23. #include <boost/asio/error.hpp>
  24. #include <boost/asio/io_service.hpp>
  25. #include <boost/asio/detail/bind_handler.hpp>
  26. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  27. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  28. #include <boost/asio/detail/mutex.hpp>
  29. #include <boost/asio/detail/win_iocp_io_service.hpp>
  30. namespace boost {
  31. namespace asio {
  32. namespace detail {
  33. class win_iocp_handle_service
  34. : public boost::asio::detail::service_base<win_iocp_handle_service>
  35. {
  36. public:
  37. // Base class for all operations.
  38. typedef win_iocp_io_service::operation operation;
  39. // The native type of a stream handle.
  40. typedef HANDLE native_type;
  41. // The implementation type of the stream handle.
  42. class implementation_type
  43. {
  44. public:
  45. // Default constructor.
  46. implementation_type()
  47. : handle_(INVALID_HANDLE_VALUE),
  48. safe_cancellation_thread_id_(0),
  49. next_(0),
  50. prev_(0)
  51. {
  52. }
  53. private:
  54. // Only this service will have access to the internal values.
  55. friend class win_iocp_handle_service;
  56. // The native stream handle representation.
  57. native_type handle_;
  58. // The ID of the thread from which it is safe to cancel asynchronous
  59. // operations. 0 means no asynchronous operations have been started yet.
  60. // ~0 means asynchronous operations have been started from more than one
  61. // thread, and cancellation is not supported for the handle.
  62. DWORD safe_cancellation_thread_id_;
  63. // Pointers to adjacent handle implementations in linked list.
  64. implementation_type* next_;
  65. implementation_type* prev_;
  66. };
  67. win_iocp_handle_service(boost::asio::io_service& io_service)
  68. : boost::asio::detail::service_base<win_iocp_handle_service>(io_service),
  69. iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
  70. mutex_(),
  71. impl_list_(0)
  72. {
  73. }
  74. // Destroy all user-defined handler objects owned by the service.
  75. void shutdown_service()
  76. {
  77. // Close all implementations, causing all operations to complete.
  78. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  79. implementation_type* impl = impl_list_;
  80. while (impl)
  81. {
  82. close_for_destruction(*impl);
  83. impl = impl->next_;
  84. }
  85. }
  86. // Construct a new handle implementation.
  87. void construct(implementation_type& impl)
  88. {
  89. impl.handle_ = INVALID_HANDLE_VALUE;
  90. impl.safe_cancellation_thread_id_ = 0;
  91. // Insert implementation into linked list of all implementations.
  92. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  93. impl.next_ = impl_list_;
  94. impl.prev_ = 0;
  95. if (impl_list_)
  96. impl_list_->prev_ = &impl;
  97. impl_list_ = &impl;
  98. }
  99. // Destroy a handle implementation.
  100. void destroy(implementation_type& impl)
  101. {
  102. close_for_destruction(impl);
  103. // Remove implementation from linked list of all implementations.
  104. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  105. if (impl_list_ == &impl)
  106. impl_list_ = impl.next_;
  107. if (impl.prev_)
  108. impl.prev_->next_ = impl.next_;
  109. if (impl.next_)
  110. impl.next_->prev_= impl.prev_;
  111. impl.next_ = 0;
  112. impl.prev_ = 0;
  113. }
  114. // Assign a native handle to a handle implementation.
  115. boost::system::error_code assign(implementation_type& impl,
  116. const native_type& native_handle, boost::system::error_code& ec)
  117. {
  118. if (is_open(impl))
  119. {
  120. ec = boost::asio::error::already_open;
  121. return ec;
  122. }
  123. if (iocp_service_.register_handle(native_handle, ec))
  124. return ec;
  125. impl.handle_ = native_handle;
  126. ec = boost::system::error_code();
  127. return ec;
  128. }
  129. // Determine whether the handle is open.
  130. bool is_open(const implementation_type& impl) const
  131. {
  132. return impl.handle_ != INVALID_HANDLE_VALUE;
  133. }
  134. // Destroy a handle implementation.
  135. boost::system::error_code close(implementation_type& impl,
  136. boost::system::error_code& ec)
  137. {
  138. if (is_open(impl))
  139. {
  140. if (!::CloseHandle(impl.handle_))
  141. {
  142. DWORD last_error = ::GetLastError();
  143. ec = boost::system::error_code(last_error,
  144. boost::asio::error::get_system_category());
  145. return ec;
  146. }
  147. impl.handle_ = INVALID_HANDLE_VALUE;
  148. impl.safe_cancellation_thread_id_ = 0;
  149. }
  150. ec = boost::system::error_code();
  151. return ec;
  152. }
  153. // Get the native handle representation.
  154. native_type native(const implementation_type& impl) const
  155. {
  156. return impl.handle_;
  157. }
  158. // Cancel all operations associated with the handle.
  159. boost::system::error_code cancel(implementation_type& impl,
  160. boost::system::error_code& ec)
  161. {
  162. if (!is_open(impl))
  163. {
  164. ec = boost::asio::error::bad_descriptor;
  165. }
  166. else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
  167. ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
  168. {
  169. // The version of Windows supports cancellation from any thread.
  170. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
  171. cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
  172. if (!cancel_io_ex(impl.handle_, 0))
  173. {
  174. DWORD last_error = ::GetLastError();
  175. if (last_error == ERROR_NOT_FOUND)
  176. {
  177. // ERROR_NOT_FOUND means that there were no operations to be
  178. // cancelled. We swallow this error to match the behaviour on other
  179. // platforms.
  180. ec = boost::system::error_code();
  181. }
  182. else
  183. {
  184. ec = boost::system::error_code(last_error,
  185. boost::asio::error::get_system_category());
  186. }
  187. }
  188. else
  189. {
  190. ec = boost::system::error_code();
  191. }
  192. }
  193. else if (impl.safe_cancellation_thread_id_ == 0)
  194. {
  195. // No operations have been started, so there's nothing to cancel.
  196. ec = boost::system::error_code();
  197. }
  198. else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
  199. {
  200. // Asynchronous operations have been started from the current thread only,
  201. // so it is safe to try to cancel them using CancelIo.
  202. if (!::CancelIo(impl.handle_))
  203. {
  204. DWORD last_error = ::GetLastError();
  205. ec = boost::system::error_code(last_error,
  206. boost::asio::error::get_system_category());
  207. }
  208. else
  209. {
  210. ec = boost::system::error_code();
  211. }
  212. }
  213. else
  214. {
  215. // Asynchronous operations have been started from more than one thread,
  216. // so cancellation is not safe.
  217. ec = boost::asio::error::operation_not_supported;
  218. }
  219. return ec;
  220. }
  221. class overlapped_wrapper
  222. : public OVERLAPPED
  223. {
  224. public:
  225. explicit overlapped_wrapper(boost::system::error_code& ec)
  226. {
  227. Internal = 0;
  228. InternalHigh = 0;
  229. Offset = 0;
  230. OffsetHigh = 0;
  231. // Create a non-signalled manual-reset event, for GetOverlappedResult.
  232. hEvent = ::CreateEvent(0, TRUE, FALSE, 0);
  233. if (hEvent)
  234. {
  235. // As documented in GetQueuedCompletionStatus, setting the low order
  236. // bit of this event prevents our synchronous writes from being treated
  237. // as completion port events.
  238. *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
  239. }
  240. else
  241. {
  242. DWORD last_error = ::GetLastError();
  243. ec = boost::system::error_code(last_error,
  244. boost::asio::error::get_system_category());
  245. }
  246. }
  247. ~overlapped_wrapper()
  248. {
  249. if (hEvent)
  250. {
  251. ::CloseHandle(hEvent);
  252. }
  253. }
  254. };
  255. // Write the given data. Returns the number of bytes written.
  256. template <typename ConstBufferSequence>
  257. size_t write_some(implementation_type& impl,
  258. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  259. {
  260. return write_some_at(impl, 0, buffers, ec);
  261. }
  262. // Write the given data at the specified offset. Returns the number of bytes
  263. // written.
  264. template <typename ConstBufferSequence>
  265. size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
  266. const ConstBufferSequence& buffers, boost::system::error_code& ec)
  267. {
  268. if (!is_open(impl))
  269. {
  270. ec = boost::asio::error::bad_descriptor;
  271. return 0;
  272. }
  273. // Find first buffer of non-zero length.
  274. boost::asio::const_buffer buffer;
  275. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  276. typename ConstBufferSequence::const_iterator end = buffers.end();
  277. for (DWORD i = 0; iter != end; ++iter, ++i)
  278. {
  279. buffer = boost::asio::const_buffer(*iter);
  280. if (boost::asio::buffer_size(buffer) != 0)
  281. break;
  282. }
  283. // A request to write 0 bytes on a handle is a no-op.
  284. if (boost::asio::buffer_size(buffer) == 0)
  285. {
  286. ec = boost::system::error_code();
  287. return 0;
  288. }
  289. overlapped_wrapper overlapped(ec);
  290. if (ec)
  291. {
  292. return 0;
  293. }
  294. // Write the data.
  295. overlapped.Offset = offset & 0xFFFFFFFF;
  296. overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
  297. BOOL ok = ::WriteFile(impl.handle_,
  298. boost::asio::buffer_cast<LPCVOID>(buffer),
  299. static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
  300. if (!ok)
  301. {
  302. DWORD last_error = ::GetLastError();
  303. if (last_error != ERROR_IO_PENDING)
  304. {
  305. ec = boost::system::error_code(last_error,
  306. boost::asio::error::get_system_category());
  307. return 0;
  308. }
  309. }
  310. // Wait for the operation to complete.
  311. DWORD bytes_transferred = 0;
  312. ok = ::GetOverlappedResult(impl.handle_,
  313. &overlapped, &bytes_transferred, TRUE);
  314. if (!ok)
  315. {
  316. DWORD last_error = ::GetLastError();
  317. ec = boost::system::error_code(last_error,
  318. boost::asio::error::get_system_category());
  319. return 0;
  320. }
  321. ec = boost::system::error_code();
  322. return bytes_transferred;
  323. }
  324. template <typename ConstBufferSequence, typename Handler>
  325. class write_operation
  326. : public operation
  327. {
  328. public:
  329. write_operation(win_iocp_io_service& io_service,
  330. const ConstBufferSequence& buffers, Handler handler)
  331. : operation(io_service,
  332. &write_operation<ConstBufferSequence, Handler>::do_completion_impl,
  333. &write_operation<ConstBufferSequence, Handler>::destroy_impl),
  334. work_(io_service.get_io_service()),
  335. buffers_(buffers),
  336. handler_(handler)
  337. {
  338. }
  339. private:
  340. static void do_completion_impl(operation* op,
  341. DWORD last_error, size_t bytes_transferred)
  342. {
  343. // Take ownership of the operation object.
  344. typedef write_operation<ConstBufferSequence, Handler> op_type;
  345. op_type* handler_op(static_cast<op_type*>(op));
  346. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  347. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  348. #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
  349. // Check whether buffers are still valid.
  350. typename ConstBufferSequence::const_iterator iter
  351. = handler_op->buffers_.begin();
  352. typename ConstBufferSequence::const_iterator end
  353. = handler_op->buffers_.end();
  354. while (iter != end)
  355. {
  356. boost::asio::const_buffer buffer(*iter);
  357. boost::asio::buffer_cast<const char*>(buffer);
  358. ++iter;
  359. }
  360. #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
  361. // Make a copy of the handler so that the memory can be deallocated before
  362. // the upcall is made.
  363. Handler handler(handler_op->handler_);
  364. // Free the memory associated with the handler.
  365. ptr.reset();
  366. // Call the handler.
  367. boost::system::error_code ec(last_error,
  368. boost::asio::error::get_system_category());
  369. boost_asio_handler_invoke_helpers::invoke(
  370. bind_handler(handler, ec, bytes_transferred), &handler);
  371. }
  372. static void destroy_impl(operation* op)
  373. {
  374. // Take ownership of the operation object.
  375. typedef write_operation<ConstBufferSequence, Handler> op_type;
  376. op_type* handler_op(static_cast<op_type*>(op));
  377. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  378. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  379. // A sub-object of the handler may be the true owner of the memory
  380. // associated with the handler. Consequently, a local copy of the handler
  381. // is required to ensure that any owning sub-object remains valid until
  382. // after we have deallocated the memory here.
  383. Handler handler(handler_op->handler_);
  384. (void)handler;
  385. // Free the memory associated with the handler.
  386. ptr.reset();
  387. }
  388. boost::asio::io_service::work work_;
  389. ConstBufferSequence buffers_;
  390. Handler handler_;
  391. };
  392. // Start an asynchronous write. The data being written must be valid for the
  393. // lifetime of the asynchronous operation.
  394. template <typename ConstBufferSequence, typename Handler>
  395. void async_write_some(implementation_type& impl,
  396. const ConstBufferSequence& buffers, Handler handler)
  397. {
  398. async_write_some_at(impl, 0, buffers, handler);
  399. }
  400. // Start an asynchronous write at a specified offset. The data being written
  401. // must be valid for the lifetime of the asynchronous operation.
  402. template <typename ConstBufferSequence, typename Handler>
  403. void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
  404. const ConstBufferSequence& buffers, Handler handler)
  405. {
  406. if (!is_open(impl))
  407. {
  408. this->get_io_service().post(bind_handler(handler,
  409. boost::asio::error::bad_descriptor, 0));
  410. return;
  411. }
  412. // Update the ID of the thread from which cancellation is safe.
  413. if (impl.safe_cancellation_thread_id_ == 0)
  414. impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
  415. else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
  416. impl.safe_cancellation_thread_id_ = ~DWORD(0);
  417. // Allocate and construct an operation to wrap the handler.
  418. typedef write_operation<ConstBufferSequence, Handler> value_type;
  419. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  420. raw_handler_ptr<alloc_traits> raw_ptr(handler);
  421. handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
  422. // Find first buffer of non-zero length.
  423. boost::asio::const_buffer buffer;
  424. typename ConstBufferSequence::const_iterator iter = buffers.begin();
  425. typename ConstBufferSequence::const_iterator end = buffers.end();
  426. for (DWORD i = 0; iter != end; ++iter, ++i)
  427. {
  428. buffer = boost::asio::const_buffer(*iter);
  429. if (boost::asio::buffer_size(buffer) != 0)
  430. break;
  431. }
  432. // A request to write 0 bytes on a handle is a no-op.
  433. if (boost::asio::buffer_size(buffer) == 0)
  434. {
  435. boost::asio::io_service::work work(this->get_io_service());
  436. ptr.reset();
  437. boost::system::error_code error;
  438. iocp_service_.post(bind_handler(handler, error, 0));
  439. return;
  440. }
  441. // Write the data.
  442. DWORD bytes_transferred = 0;
  443. ptr.get()->Offset = offset & 0xFFFFFFFF;
  444. ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
  445. BOOL ok = ::WriteFile(impl.handle_,
  446. boost::asio::buffer_cast<LPCVOID>(buffer),
  447. static_cast<DWORD>(boost::asio::buffer_size(buffer)),
  448. &bytes_transferred, ptr.get());
  449. DWORD last_error = ::GetLastError();
  450. // Check if the operation completed immediately.
  451. if (!ok && last_error != ERROR_IO_PENDING)
  452. {
  453. boost::asio::io_service::work work(this->get_io_service());
  454. ptr.reset();
  455. boost::system::error_code ec(last_error,
  456. boost::asio::error::get_system_category());
  457. iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
  458. }
  459. else
  460. {
  461. ptr.release();
  462. }
  463. }
  464. // Read some data. Returns the number of bytes received.
  465. template <typename MutableBufferSequence>
  466. size_t read_some(implementation_type& impl,
  467. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  468. {
  469. return read_some_at(impl, 0, buffers, ec);
  470. }
  471. // Read some data at a specified offset. Returns the number of bytes received.
  472. template <typename MutableBufferSequence>
  473. size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
  474. const MutableBufferSequence& buffers, boost::system::error_code& ec)
  475. {
  476. if (!is_open(impl))
  477. {
  478. ec = boost::asio::error::bad_descriptor;
  479. return 0;
  480. }
  481. // Find first buffer of non-zero length.
  482. boost::asio::mutable_buffer buffer;
  483. typename MutableBufferSequence::const_iterator iter = buffers.begin();
  484. typename MutableBufferSequence::const_iterator end = buffers.end();
  485. for (DWORD i = 0; iter != end; ++iter, ++i)
  486. {
  487. buffer = boost::asio::mutable_buffer(*iter);
  488. if (boost::asio::buffer_size(buffer) != 0)
  489. break;
  490. }
  491. // A request to read 0 bytes on a stream handle is a no-op.
  492. if (boost::asio::buffer_size(buffer) == 0)
  493. {
  494. ec = boost::system::error_code();
  495. return 0;
  496. }
  497. overlapped_wrapper overlapped(ec);
  498. if (ec)
  499. {
  500. return 0;
  501. }
  502. // Read some data.
  503. overlapped.Offset = offset & 0xFFFFFFFF;
  504. overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
  505. BOOL ok = ::ReadFile(impl.handle_,
  506. boost::asio::buffer_cast<LPVOID>(buffer),
  507. static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
  508. if (!ok)
  509. {
  510. DWORD last_error = ::GetLastError();
  511. if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
  512. {
  513. if (last_error == ERROR_HANDLE_EOF)
  514. {
  515. ec = boost::asio::error::eof;
  516. }
  517. else
  518. {
  519. ec = boost::system::error_code(last_error,
  520. boost::asio::error::get_system_category());
  521. }
  522. return 0;
  523. }
  524. }
  525. // Wait for the operation to complete.
  526. DWORD bytes_transferred = 0;
  527. ok = ::GetOverlappedResult(impl.handle_,
  528. &overlapped, &bytes_transferred, TRUE);
  529. if (!ok)
  530. {
  531. DWORD last_error = ::GetLastError();
  532. if (last_error == ERROR_HANDLE_EOF)
  533. {
  534. ec = boost::asio::error::eof;
  535. }
  536. else
  537. {
  538. ec = boost::system::error_code(last_error,
  539. boost::asio::error::get_system_category());
  540. }
  541. return 0;
  542. }
  543. ec = boost::system::error_code();
  544. return bytes_transferred;
  545. }
  546. template <typename MutableBufferSequence, typename Handler>
  547. class read_operation
  548. : public operation
  549. {
  550. public:
  551. read_operation(win_iocp_io_service& io_service,
  552. const MutableBufferSequence& buffers, Handler handler)
  553. : operation(io_service,
  554. &read_operation<
  555. MutableBufferSequence, Handler>::do_completion_impl,
  556. &read_operation<
  557. MutableBufferSequence, Handler>::destroy_impl),
  558. work_(io_service.get_io_service()),
  559. buffers_(buffers),
  560. handler_(handler)
  561. {
  562. }
  563. private:
  564. static void do_completion_impl(operation* op,
  565. DWORD last_error, size_t bytes_transferred)
  566. {
  567. // Take ownership of the operation object.
  568. typedef read_operation<MutableBufferSequence, Handler> op_type;
  569. op_type* handler_op(static_cast<op_type*>(op));
  570. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  571. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  572. #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
  573. // Check whether buffers are still valid.
  574. typename MutableBufferSequence::const_iterator iter
  575. = handler_op->buffers_.begin();
  576. typename MutableBufferSequence::const_iterator end
  577. = handler_op->buffers_.end();
  578. while (iter != end)
  579. {
  580. boost::asio::mutable_buffer buffer(*iter);
  581. boost::asio::buffer_cast<char*>(buffer);
  582. ++iter;
  583. }
  584. #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
  585. // Check for the end-of-file condition.
  586. boost::system::error_code ec(last_error,
  587. boost::asio::error::get_system_category());
  588. if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF)
  589. {
  590. ec = boost::asio::error::eof;
  591. }
  592. // Make a copy of the handler so that the memory can be deallocated before
  593. // the upcall is made.
  594. Handler handler(handler_op->handler_);
  595. // Free the memory associated with the handler.
  596. ptr.reset();
  597. // Call the handler.
  598. boost_asio_handler_invoke_helpers::invoke(
  599. bind_handler(handler, ec, bytes_transferred), &handler);
  600. }
  601. static void destroy_impl(operation* op)
  602. {
  603. // Take ownership of the operation object.
  604. typedef read_operation<MutableBufferSequence, Handler> op_type;
  605. op_type* handler_op(static_cast<op_type*>(op));
  606. typedef boost::asio::detail::handler_alloc_traits<
  607. Handler, op_type> alloc_traits;
  608. boost::asio::detail::handler_ptr<alloc_traits> ptr(
  609. handler_op->handler_, handler_op);
  610. // A sub-object of the handler may be the true owner of the memory
  611. // associated with the handler. Consequently, a local copy of the handler
  612. // is required to ensure that any owning sub-object remains valid until
  613. // after we have deallocated the memory here.
  614. Handler handler(handler_op->handler_);
  615. (void)handler;
  616. // Free the memory associated with the handler.
  617. ptr.reset();
  618. }
  619. boost::asio::io_service::work work_;
  620. MutableBufferSequence buffers_;
  621. Handler handler_;
  622. };
  623. // Start an asynchronous read. The buffer for the data being received must be
  624. // valid for the lifetime of the asynchronous operation.
  625. template <typename MutableBufferSequence, typename Handler>
  626. void async_read_some(implementation_type& impl,
  627. const MutableBufferSequence& buffers, Handler handler)
  628. {
  629. async_read_some_at(impl, 0, buffers, handler);
  630. }
  631. // Start an asynchronous read at a specified offset. The buffer for the data
  632. // being received must be valid for the lifetime of the asynchronous
  633. // operation.
  634. template <typename MutableBufferSequence, typename Handler>
  635. void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
  636. const MutableBufferSequence& buffers, Handler handler)
  637. {
  638. if (!is_open(impl))
  639. {
  640. this->get_io_service().post(bind_handler(handler,
  641. boost::asio::error::bad_descriptor, 0));
  642. return;
  643. }
  644. // Update the ID of the thread from which cancellation is safe.
  645. if (impl.safe_cancellation_thread_id_ == 0)
  646. impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
  647. else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
  648. impl.safe_cancellation_thread_id_ = ~DWORD(0);
  649. // Allocate and construct an operation to wrap the handler.
  650. typedef read_operation<MutableBufferSequence, Handler> value_type;
  651. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  652. raw_handler_ptr<alloc_traits> raw_ptr(handler);
  653. handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
  654. // Find first buffer of non-zero length.
  655. boost::asio::mutable_buffer buffer;
  656. typename MutableBufferSequence::const_iterator iter = buffers.begin();
  657. typename MutableBufferSequence::const_iterator end = buffers.end();
  658. for (DWORD i = 0; iter != end; ++iter, ++i)
  659. {
  660. buffer = boost::asio::mutable_buffer(*iter);
  661. if (boost::asio::buffer_size(buffer) != 0)
  662. break;
  663. }
  664. // A request to receive 0 bytes on a stream handle is a no-op.
  665. if (boost::asio::buffer_size(buffer) == 0)
  666. {
  667. boost::asio::io_service::work work(this->get_io_service());
  668. ptr.reset();
  669. boost::system::error_code error;
  670. iocp_service_.post(bind_handler(handler, error, 0));
  671. return;
  672. }
  673. // Read some data.
  674. DWORD bytes_transferred = 0;
  675. ptr.get()->Offset = offset & 0xFFFFFFFF;
  676. ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
  677. BOOL ok = ::ReadFile(impl.handle_,
  678. boost::asio::buffer_cast<LPVOID>(buffer),
  679. static_cast<DWORD>(boost::asio::buffer_size(buffer)),
  680. &bytes_transferred, ptr.get());
  681. DWORD last_error = ::GetLastError();
  682. if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
  683. {
  684. boost::asio::io_service::work work(this->get_io_service());
  685. ptr.reset();
  686. boost::system::error_code ec(last_error,
  687. boost::asio::error::get_system_category());
  688. iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
  689. }
  690. else
  691. {
  692. ptr.release();
  693. }
  694. }
  695. private:
  696. // Prevent the use of the null_buffers type with this service.
  697. size_t write_some(implementation_type& impl,
  698. const null_buffers& buffers, boost::system::error_code& ec);
  699. size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
  700. const null_buffers& buffers, boost::system::error_code& ec);
  701. template <typename Handler>
  702. void async_write_some(implementation_type& impl,
  703. const null_buffers& buffers, Handler handler);
  704. template <typename Handler>
  705. void async_write_some_at(implementation_type& impl, boost::uint64_t offset,
  706. const null_buffers& buffers, Handler handler);
  707. size_t read_some(implementation_type& impl,
  708. const null_buffers& buffers, boost::system::error_code& ec);
  709. size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
  710. const null_buffers& buffers, boost::system::error_code& ec);
  711. template <typename Handler>
  712. void async_read_some(implementation_type& impl,
  713. const null_buffers& buffers, Handler handler);
  714. template <typename Handler>
  715. void async_read_some_at(implementation_type& impl, boost::uint64_t offset,
  716. const null_buffers& buffers, Handler handler);
  717. // Helper function to close a handle when the associated object is being
  718. // destroyed.
  719. void close_for_destruction(implementation_type& impl)
  720. {
  721. if (is_open(impl))
  722. {
  723. ::CloseHandle(impl.handle_);
  724. impl.handle_ = INVALID_HANDLE_VALUE;
  725. impl.safe_cancellation_thread_id_ = 0;
  726. }
  727. }
  728. // The IOCP service used for running asynchronous operations and dispatching
  729. // handlers.
  730. win_iocp_io_service& iocp_service_;
  731. // Mutex to protect access to the linked list of implementations.
  732. boost::asio::detail::mutex mutex_;
  733. // The head of a linked list of all implementations.
  734. implementation_type* impl_list_;
  735. };
  736. } // namespace detail
  737. } // namespace asio
  738. } // namespace boost
  739. #endif // defined(BOOST_ASIO_HAS_IOCP)
  740. #include <boost/asio/detail/pop_options.hpp>
  741. #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP