win_iocp_handle_service.hpp 22 KB

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