win_iocp_io_service.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. //
  2. // win_iocp_io_service.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_IO_SERVICE_HPP
  11. #define BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_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/push_options.hpp>
  19. #include <limits>
  20. #include <boost/throw_exception.hpp>
  21. #include <boost/system/system_error.hpp>
  22. #include <boost/asio/detail/pop_options.hpp>
  23. #include <boost/asio/io_service.hpp>
  24. #include <boost/asio/detail/call_stack.hpp>
  25. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  26. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  27. #include <boost/asio/detail/service_base.hpp>
  28. #include <boost/asio/detail/socket_types.hpp>
  29. #include <boost/asio/detail/timer_queue.hpp>
  30. #include <boost/asio/detail/mutex.hpp>
  31. namespace boost {
  32. namespace asio {
  33. namespace detail {
  34. class win_iocp_io_service
  35. : public boost::asio::detail::service_base<win_iocp_io_service>
  36. {
  37. public:
  38. // Base class for all operations. A function pointer is used instead of
  39. // virtual functions to avoid the associated overhead.
  40. //
  41. // This class inherits from OVERLAPPED so that we can downcast to get back to
  42. // the operation pointer from the LPOVERLAPPED out parameter of
  43. // GetQueuedCompletionStatus.
  44. class operation
  45. : public OVERLAPPED
  46. {
  47. public:
  48. typedef void (*invoke_func_type)(operation*, DWORD, size_t);
  49. typedef void (*destroy_func_type)(operation*);
  50. operation(win_iocp_io_service& iocp_service,
  51. invoke_func_type invoke_func, destroy_func_type destroy_func)
  52. : outstanding_operations_(&iocp_service.outstanding_operations_),
  53. invoke_func_(invoke_func),
  54. destroy_func_(destroy_func)
  55. {
  56. Internal = 0;
  57. InternalHigh = 0;
  58. Offset = 0;
  59. OffsetHigh = 0;
  60. hEvent = 0;
  61. ::InterlockedIncrement(outstanding_operations_);
  62. }
  63. void do_completion(DWORD last_error, size_t bytes_transferred)
  64. {
  65. invoke_func_(this, last_error, bytes_transferred);
  66. }
  67. void destroy()
  68. {
  69. destroy_func_(this);
  70. }
  71. protected:
  72. // Prevent deletion through this type.
  73. ~operation()
  74. {
  75. ::InterlockedDecrement(outstanding_operations_);
  76. }
  77. private:
  78. long* outstanding_operations_;
  79. invoke_func_type invoke_func_;
  80. destroy_func_type destroy_func_;
  81. };
  82. // Constructor.
  83. win_iocp_io_service(boost::asio::io_service& io_service)
  84. : boost::asio::detail::service_base<win_iocp_io_service>(io_service),
  85. iocp_(),
  86. outstanding_work_(0),
  87. outstanding_operations_(0),
  88. stopped_(0),
  89. shutdown_(0),
  90. timer_thread_(0),
  91. timer_interrupt_issued_(false)
  92. {
  93. }
  94. void init(size_t concurrency_hint)
  95. {
  96. iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
  97. static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
  98. if (!iocp_.handle)
  99. {
  100. DWORD last_error = ::GetLastError();
  101. boost::system::system_error e(
  102. boost::system::error_code(last_error,
  103. boost::asio::error::get_system_category()),
  104. "iocp");
  105. boost::throw_exception(e);
  106. }
  107. }
  108. // Destroy all user-defined handler objects owned by the service.
  109. void shutdown_service()
  110. {
  111. ::InterlockedExchange(&shutdown_, 1);
  112. while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
  113. {
  114. DWORD bytes_transferred = 0;
  115. #if defined(WINVER) && (WINVER < 0x0500)
  116. DWORD completion_key = 0;
  117. #else
  118. DWORD_PTR completion_key = 0;
  119. #endif
  120. LPOVERLAPPED overlapped = 0;
  121. ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
  122. &completion_key, &overlapped, INFINITE);
  123. if (overlapped)
  124. static_cast<operation*>(overlapped)->destroy();
  125. }
  126. for (std::size_t i = 0; i < timer_queues_.size(); ++i)
  127. timer_queues_[i]->destroy_timers();
  128. timer_queues_.clear();
  129. }
  130. // Initialise the task. Nothing to do here.
  131. void init_task()
  132. {
  133. }
  134. // Register a handle with the IO completion port.
  135. boost::system::error_code register_handle(
  136. HANDLE handle, boost::system::error_code& ec)
  137. {
  138. if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
  139. {
  140. DWORD last_error = ::GetLastError();
  141. ec = boost::system::error_code(last_error,
  142. boost::asio::error::get_system_category());
  143. }
  144. else
  145. {
  146. ec = boost::system::error_code();
  147. }
  148. return ec;
  149. }
  150. // Run the event loop until stopped or no more work.
  151. size_t run(boost::system::error_code& ec)
  152. {
  153. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  154. {
  155. ec = boost::system::error_code();
  156. return 0;
  157. }
  158. call_stack<win_iocp_io_service>::context ctx(this);
  159. size_t n = 0;
  160. while (do_one(true, ec))
  161. if (n != (std::numeric_limits<size_t>::max)())
  162. ++n;
  163. return n;
  164. }
  165. // Run until stopped or one operation is performed.
  166. size_t run_one(boost::system::error_code& ec)
  167. {
  168. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  169. {
  170. ec = boost::system::error_code();
  171. return 0;
  172. }
  173. call_stack<win_iocp_io_service>::context ctx(this);
  174. return do_one(true, ec);
  175. }
  176. // Poll for operations without blocking.
  177. size_t poll(boost::system::error_code& ec)
  178. {
  179. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  180. {
  181. ec = boost::system::error_code();
  182. return 0;
  183. }
  184. call_stack<win_iocp_io_service>::context ctx(this);
  185. size_t n = 0;
  186. while (do_one(false, ec))
  187. if (n != (std::numeric_limits<size_t>::max)())
  188. ++n;
  189. return n;
  190. }
  191. // Poll for one operation without blocking.
  192. size_t poll_one(boost::system::error_code& ec)
  193. {
  194. if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
  195. {
  196. ec = boost::system::error_code();
  197. return 0;
  198. }
  199. call_stack<win_iocp_io_service>::context ctx(this);
  200. return do_one(false, ec);
  201. }
  202. // Stop the event processing loop.
  203. void stop()
  204. {
  205. if (::InterlockedExchange(&stopped_, 1) == 0)
  206. {
  207. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
  208. {
  209. DWORD last_error = ::GetLastError();
  210. boost::system::system_error e(
  211. boost::system::error_code(last_error,
  212. boost::asio::error::get_system_category()),
  213. "pqcs");
  214. boost::throw_exception(e);
  215. }
  216. }
  217. }
  218. // Reset in preparation for a subsequent run invocation.
  219. void reset()
  220. {
  221. ::InterlockedExchange(&stopped_, 0);
  222. }
  223. // Notify that some work has started.
  224. void work_started()
  225. {
  226. ::InterlockedIncrement(&outstanding_work_);
  227. }
  228. // Notify that some work has finished.
  229. void work_finished()
  230. {
  231. if (::InterlockedDecrement(&outstanding_work_) == 0)
  232. stop();
  233. }
  234. // Request invocation of the given handler.
  235. template <typename Handler>
  236. void dispatch(Handler handler)
  237. {
  238. if (call_stack<win_iocp_io_service>::contains(this))
  239. boost_asio_handler_invoke_helpers::invoke(handler, &handler);
  240. else
  241. post(handler);
  242. }
  243. // Request invocation of the given handler and return immediately.
  244. template <typename Handler>
  245. void post(Handler handler)
  246. {
  247. // If the service has been shut down we silently discard the handler.
  248. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
  249. return;
  250. // Allocate and construct an operation to wrap the handler.
  251. typedef handler_operation<Handler> value_type;
  252. typedef handler_alloc_traits<Handler, value_type> alloc_traits;
  253. raw_handler_ptr<alloc_traits> raw_ptr(handler);
  254. handler_ptr<alloc_traits> ptr(raw_ptr, *this, handler);
  255. // Enqueue the operation on the I/O completion port.
  256. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
  257. {
  258. DWORD last_error = ::GetLastError();
  259. boost::system::system_error e(
  260. boost::system::error_code(last_error,
  261. boost::asio::error::get_system_category()),
  262. "pqcs");
  263. boost::throw_exception(e);
  264. }
  265. // Operation has been successfully posted.
  266. ptr.release();
  267. }
  268. // Request invocation of the given OVERLAPPED-derived operation.
  269. void post_completion(operation* op, DWORD op_last_error,
  270. DWORD bytes_transferred)
  271. {
  272. // Enqueue the operation on the I/O completion port.
  273. if (!::PostQueuedCompletionStatus(iocp_.handle,
  274. bytes_transferred, op_last_error, op))
  275. {
  276. DWORD last_error = ::GetLastError();
  277. boost::system::system_error e(
  278. boost::system::error_code(last_error,
  279. boost::asio::error::get_system_category()),
  280. "pqcs");
  281. boost::throw_exception(e);
  282. }
  283. }
  284. // Add a new timer queue to the service.
  285. template <typename Time_Traits>
  286. void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
  287. {
  288. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  289. timer_queues_.push_back(&timer_queue);
  290. }
  291. // Remove a timer queue from the service.
  292. template <typename Time_Traits>
  293. void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
  294. {
  295. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  296. for (std::size_t i = 0; i < timer_queues_.size(); ++i)
  297. {
  298. if (timer_queues_[i] == &timer_queue)
  299. {
  300. timer_queues_.erase(timer_queues_.begin() + i);
  301. return;
  302. }
  303. }
  304. }
  305. // Schedule a timer in the given timer queue to expire at the specified
  306. // absolute time. The handler object will be invoked when the timer expires.
  307. template <typename Time_Traits, typename Handler>
  308. void schedule_timer(timer_queue<Time_Traits>& timer_queue,
  309. const typename Time_Traits::time_type& time, Handler handler, void* token)
  310. {
  311. // If the service has been shut down we silently discard the timer.
  312. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
  313. return;
  314. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  315. if (timer_queue.enqueue_timer(time, handler, token))
  316. {
  317. if (!timer_interrupt_issued_)
  318. {
  319. timer_interrupt_issued_ = true;
  320. lock.unlock();
  321. ::PostQueuedCompletionStatus(iocp_.handle,
  322. 0, steal_timer_dispatching, 0);
  323. }
  324. }
  325. }
  326. // Cancel the timer associated with the given token. Returns the number of
  327. // handlers that have been posted or dispatched.
  328. template <typename Time_Traits>
  329. std::size_t cancel_timer(timer_queue<Time_Traits>& timer_queue, void* token)
  330. {
  331. // If the service has been shut down we silently ignore the cancellation.
  332. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
  333. return 0;
  334. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  335. std::size_t n = timer_queue.cancel_timer(token);
  336. if (n > 0 && !timer_interrupt_issued_)
  337. {
  338. timer_interrupt_issued_ = true;
  339. lock.unlock();
  340. ::PostQueuedCompletionStatus(iocp_.handle,
  341. 0, steal_timer_dispatching, 0);
  342. }
  343. return n;
  344. }
  345. private:
  346. // Dequeues at most one operation from the I/O completion port, and then
  347. // executes it. Returns the number of operations that were dequeued (i.e.
  348. // either 0 or 1).
  349. size_t do_one(bool block, boost::system::error_code& ec)
  350. {
  351. long this_thread_id = static_cast<long>(::GetCurrentThreadId());
  352. for (;;)
  353. {
  354. // Try to acquire responsibility for dispatching timers.
  355. bool dispatching_timers = (::InterlockedCompareExchange(
  356. &timer_thread_, this_thread_id, 0) == 0);
  357. // Calculate timeout for GetQueuedCompletionStatus call.
  358. DWORD timeout = max_timeout;
  359. if (dispatching_timers)
  360. {
  361. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  362. timer_interrupt_issued_ = false;
  363. timeout = get_timeout();
  364. }
  365. // Get the next operation from the queue.
  366. DWORD bytes_transferred = 0;
  367. #if defined(WINVER) && (WINVER < 0x0500)
  368. DWORD completion_key = 0;
  369. #else
  370. DWORD_PTR completion_key = 0;
  371. #endif
  372. LPOVERLAPPED overlapped = 0;
  373. ::SetLastError(0);
  374. BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
  375. &completion_key, &overlapped, block ? timeout : 0);
  376. DWORD last_error = ::GetLastError();
  377. // Dispatch any pending timers.
  378. if (dispatching_timers)
  379. {
  380. try
  381. {
  382. boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
  383. if (!timer_queues_.empty())
  384. {
  385. timer_queues_copy_ = timer_queues_;
  386. for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
  387. {
  388. timer_queues_copy_[i]->dispatch_timers();
  389. timer_queues_copy_[i]->dispatch_cancellations();
  390. timer_queues_copy_[i]->complete_timers();
  391. }
  392. }
  393. }
  394. catch (...)
  395. {
  396. // Transfer responsibility for dispatching timers to another thread.
  397. if (::InterlockedCompareExchange(&timer_thread_,
  398. 0, this_thread_id) == this_thread_id)
  399. {
  400. ::PostQueuedCompletionStatus(iocp_.handle,
  401. 0, transfer_timer_dispatching, 0);
  402. }
  403. throw;
  404. }
  405. }
  406. if (!ok && overlapped == 0)
  407. {
  408. if (block && last_error == WAIT_TIMEOUT)
  409. {
  410. // Relinquish responsibility for dispatching timers.
  411. if (dispatching_timers)
  412. {
  413. ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
  414. }
  415. continue;
  416. }
  417. // Transfer responsibility for dispatching timers to another thread.
  418. if (dispatching_timers && ::InterlockedCompareExchange(
  419. &timer_thread_, 0, this_thread_id) == this_thread_id)
  420. {
  421. ::PostQueuedCompletionStatus(iocp_.handle,
  422. 0, transfer_timer_dispatching, 0);
  423. }
  424. ec = boost::system::error_code();
  425. return 0;
  426. }
  427. else if (overlapped)
  428. {
  429. // We may have been passed a last_error value in the completion_key.
  430. if (last_error == 0)
  431. {
  432. last_error = completion_key;
  433. }
  434. // Transfer responsibility for dispatching timers to another thread.
  435. if (dispatching_timers && ::InterlockedCompareExchange(
  436. &timer_thread_, 0, this_thread_id) == this_thread_id)
  437. {
  438. ::PostQueuedCompletionStatus(iocp_.handle,
  439. 0, transfer_timer_dispatching, 0);
  440. }
  441. // Ensure that the io_service does not exit due to running out of work
  442. // while we make the upcall.
  443. auto_work work(*this);
  444. // Dispatch the operation.
  445. operation* op = static_cast<operation*>(overlapped);
  446. op->do_completion(last_error, bytes_transferred);
  447. ec = boost::system::error_code();
  448. return 1;
  449. }
  450. else if (completion_key == transfer_timer_dispatching)
  451. {
  452. // Woken up to try to acquire responsibility for dispatching timers.
  453. ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
  454. }
  455. else if (completion_key == steal_timer_dispatching)
  456. {
  457. // Woken up to steal responsibility for dispatching timers.
  458. ::InterlockedExchange(&timer_thread_, 0);
  459. }
  460. else
  461. {
  462. // Relinquish responsibility for dispatching timers. If the io_service
  463. // is not being stopped then the thread will get an opportunity to
  464. // reacquire timer responsibility on the next loop iteration.
  465. if (dispatching_timers)
  466. {
  467. ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
  468. }
  469. // The stopped_ flag is always checked to ensure that any leftover
  470. // interrupts from a previous run invocation are ignored.
  471. if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
  472. {
  473. // Wake up next thread that is blocked on GetQueuedCompletionStatus.
  474. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
  475. {
  476. last_error = ::GetLastError();
  477. ec = boost::system::error_code(last_error,
  478. boost::asio::error::get_system_category());
  479. return 0;
  480. }
  481. ec = boost::system::error_code();
  482. return 0;
  483. }
  484. }
  485. }
  486. }
  487. // Check if all timer queues are empty.
  488. bool all_timer_queues_are_empty() const
  489. {
  490. for (std::size_t i = 0; i < timer_queues_.size(); ++i)
  491. if (!timer_queues_[i]->empty())
  492. return false;
  493. return true;
  494. }
  495. // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
  496. // value is returned as a number of milliseconds. We will wait no longer than
  497. // 1000 milliseconds.
  498. DWORD get_timeout()
  499. {
  500. if (all_timer_queues_are_empty())
  501. return max_timeout;
  502. boost::posix_time::time_duration minimum_wait_duration
  503. = boost::posix_time::milliseconds(max_timeout);
  504. for (std::size_t i = 0; i < timer_queues_.size(); ++i)
  505. {
  506. boost::posix_time::time_duration wait_duration
  507. = timer_queues_[i]->wait_duration();
  508. if (wait_duration < minimum_wait_duration)
  509. minimum_wait_duration = wait_duration;
  510. }
  511. if (minimum_wait_duration > boost::posix_time::time_duration())
  512. {
  513. int milliseconds = minimum_wait_duration.total_milliseconds();
  514. return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
  515. }
  516. else
  517. {
  518. return 0;
  519. }
  520. }
  521. struct auto_work
  522. {
  523. auto_work(win_iocp_io_service& io_service)
  524. : io_service_(io_service)
  525. {
  526. io_service_.work_started();
  527. }
  528. ~auto_work()
  529. {
  530. io_service_.work_finished();
  531. }
  532. private:
  533. win_iocp_io_service& io_service_;
  534. };
  535. template <typename Handler>
  536. struct handler_operation
  537. : public operation
  538. {
  539. handler_operation(win_iocp_io_service& io_service,
  540. Handler handler)
  541. : operation(io_service, &handler_operation<Handler>::do_completion_impl,
  542. &handler_operation<Handler>::destroy_impl),
  543. io_service_(io_service),
  544. handler_(handler)
  545. {
  546. io_service_.work_started();
  547. }
  548. ~handler_operation()
  549. {
  550. io_service_.work_finished();
  551. }
  552. private:
  553. // Prevent copying and assignment.
  554. handler_operation(const handler_operation&);
  555. void operator=(const handler_operation&);
  556. static void do_completion_impl(operation* op, DWORD, size_t)
  557. {
  558. // Take ownership of the operation object.
  559. typedef handler_operation<Handler> op_type;
  560. op_type* handler_op(static_cast<op_type*>(op));
  561. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  562. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  563. // Make a copy of the handler so that the memory can be deallocated before
  564. // the upcall is made.
  565. Handler handler(handler_op->handler_);
  566. // Free the memory associated with the handler.
  567. ptr.reset();
  568. // Make the upcall.
  569. boost_asio_handler_invoke_helpers::invoke(handler, &handler);
  570. }
  571. static void destroy_impl(operation* op)
  572. {
  573. // Take ownership of the operation object.
  574. typedef handler_operation<Handler> op_type;
  575. op_type* handler_op(static_cast<op_type*>(op));
  576. typedef handler_alloc_traits<Handler, op_type> alloc_traits;
  577. handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
  578. // A sub-object of the handler may be the true owner of the memory
  579. // associated with the handler. Consequently, a local copy of the handler
  580. // is required to ensure that any owning sub-object remains valid until
  581. // after we have deallocated the memory here.
  582. Handler handler(handler_op->handler_);
  583. (void)handler;
  584. // Free the memory associated with the handler.
  585. ptr.reset();
  586. }
  587. win_iocp_io_service& io_service_;
  588. Handler handler_;
  589. };
  590. // The IO completion port used for queueing operations.
  591. struct iocp_holder
  592. {
  593. HANDLE handle;
  594. iocp_holder() : handle(0) {}
  595. ~iocp_holder() { if (handle) ::CloseHandle(handle); }
  596. } iocp_;
  597. // The count of unfinished work.
  598. long outstanding_work_;
  599. // The count of unfinished operations.
  600. long outstanding_operations_;
  601. friend class operation;
  602. // Flag to indicate whether the event loop has been stopped.
  603. long stopped_;
  604. // Flag to indicate whether the service has been shut down.
  605. long shutdown_;
  606. enum
  607. {
  608. // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
  609. max_timeout = 500,
  610. // Completion key value to indicate that responsibility for dispatching
  611. // timers is being cooperatively transferred from one thread to another.
  612. transfer_timer_dispatching = 1,
  613. // Completion key value to indicate that responsibility for dispatching
  614. // timers should be stolen from another thread.
  615. steal_timer_dispatching = 2
  616. };
  617. // The thread that's currently in charge of dispatching timers.
  618. long timer_thread_;
  619. // Mutex for protecting access to the timer queues.
  620. mutex timer_mutex_;
  621. // Whether a thread has been interrupted to process a new timeout.
  622. bool timer_interrupt_issued_;
  623. // The timer queues.
  624. std::vector<timer_queue_base*> timer_queues_;
  625. // A copy of the timer queues, used when dispatching, cancelling and cleaning
  626. // up timers. The copy is stored as a class data member to avoid unnecessary
  627. // memory allocation.
  628. std::vector<timer_queue_base*> timer_queues_copy_;
  629. };
  630. } // namespace detail
  631. } // namespace asio
  632. } // namespace boost
  633. #endif // defined(BOOST_ASIO_HAS_IOCP)
  634. #include <boost/asio/detail/pop_options.hpp>
  635. #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP