win_object_handle_service.ipp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. //
  2. // detail/impl/win_object_handle_service.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. // Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
  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_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
  12. #define BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
  13. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  14. # pragma once
  15. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  16. #include <boost/asio/detail/config.hpp>
  17. #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
  18. #include <boost/asio/detail/win_object_handle_service.hpp>
  19. #include <boost/asio/detail/push_options.hpp>
  20. namespace boost {
  21. namespace asio {
  22. namespace detail {
  23. win_object_handle_service::win_object_handle_service(
  24. boost::asio::io_context& io_context)
  25. : service_base<win_object_handle_service>(io_context),
  26. io_context_(boost::asio::use_service<io_context_impl>(io_context)),
  27. mutex_(),
  28. impl_list_(0),
  29. shutdown_(false)
  30. {
  31. }
  32. void win_object_handle_service::shutdown()
  33. {
  34. mutex::scoped_lock lock(mutex_);
  35. // Setting this flag to true prevents new objects from being registered, and
  36. // new asynchronous wait operations from being started. We only need to worry
  37. // about cleaning up the operations that are currently in progress.
  38. shutdown_ = true;
  39. op_queue<operation> ops;
  40. for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
  41. ops.push(impl->op_queue_);
  42. lock.unlock();
  43. io_context_.abandon_operations(ops);
  44. }
  45. void win_object_handle_service::construct(
  46. win_object_handle_service::implementation_type& impl)
  47. {
  48. impl.handle_ = INVALID_HANDLE_VALUE;
  49. impl.wait_handle_ = INVALID_HANDLE_VALUE;
  50. impl.owner_ = this;
  51. // Insert implementation into linked list of all implementations.
  52. mutex::scoped_lock lock(mutex_);
  53. if (!shutdown_)
  54. {
  55. impl.next_ = impl_list_;
  56. impl.prev_ = 0;
  57. if (impl_list_)
  58. impl_list_->prev_ = &impl;
  59. impl_list_ = &impl;
  60. }
  61. }
  62. void win_object_handle_service::move_construct(
  63. win_object_handle_service::implementation_type& impl,
  64. win_object_handle_service::implementation_type& other_impl)
  65. {
  66. mutex::scoped_lock lock(mutex_);
  67. // Insert implementation into linked list of all implementations.
  68. if (!shutdown_)
  69. {
  70. impl.next_ = impl_list_;
  71. impl.prev_ = 0;
  72. if (impl_list_)
  73. impl_list_->prev_ = &impl;
  74. impl_list_ = &impl;
  75. }
  76. impl.handle_ = other_impl.handle_;
  77. other_impl.handle_ = INVALID_HANDLE_VALUE;
  78. impl.wait_handle_ = other_impl.wait_handle_;
  79. other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
  80. impl.op_queue_.push(other_impl.op_queue_);
  81. impl.owner_ = this;
  82. // We must not hold the lock while calling UnregisterWaitEx. This is because
  83. // the registered callback function might be invoked while we are waiting for
  84. // UnregisterWaitEx to complete.
  85. lock.unlock();
  86. if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
  87. ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
  88. if (!impl.op_queue_.empty())
  89. register_wait_callback(impl, lock);
  90. }
  91. void win_object_handle_service::move_assign(
  92. win_object_handle_service::implementation_type& impl,
  93. win_object_handle_service& other_service,
  94. win_object_handle_service::implementation_type& other_impl)
  95. {
  96. boost::system::error_code ignored_ec;
  97. close(impl, ignored_ec);
  98. mutex::scoped_lock lock(mutex_);
  99. if (this != &other_service)
  100. {
  101. // Remove implementation from linked list of all implementations.
  102. if (impl_list_ == &impl)
  103. impl_list_ = impl.next_;
  104. if (impl.prev_)
  105. impl.prev_->next_ = impl.next_;
  106. if (impl.next_)
  107. impl.next_->prev_= impl.prev_;
  108. impl.next_ = 0;
  109. impl.prev_ = 0;
  110. }
  111. impl.handle_ = other_impl.handle_;
  112. other_impl.handle_ = INVALID_HANDLE_VALUE;
  113. impl.wait_handle_ = other_impl.wait_handle_;
  114. other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
  115. impl.op_queue_.push(other_impl.op_queue_);
  116. impl.owner_ = this;
  117. if (this != &other_service)
  118. {
  119. // Insert implementation into linked list of all implementations.
  120. impl.next_ = other_service.impl_list_;
  121. impl.prev_ = 0;
  122. if (other_service.impl_list_)
  123. other_service.impl_list_->prev_ = &impl;
  124. other_service.impl_list_ = &impl;
  125. }
  126. // We must not hold the lock while calling UnregisterWaitEx. This is because
  127. // the registered callback function might be invoked while we are waiting for
  128. // UnregisterWaitEx to complete.
  129. lock.unlock();
  130. if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
  131. ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
  132. if (!impl.op_queue_.empty())
  133. register_wait_callback(impl, lock);
  134. }
  135. void win_object_handle_service::destroy(
  136. win_object_handle_service::implementation_type& impl)
  137. {
  138. mutex::scoped_lock lock(mutex_);
  139. // Remove implementation from linked list of all implementations.
  140. if (impl_list_ == &impl)
  141. impl_list_ = impl.next_;
  142. if (impl.prev_)
  143. impl.prev_->next_ = impl.next_;
  144. if (impl.next_)
  145. impl.next_->prev_= impl.prev_;
  146. impl.next_ = 0;
  147. impl.prev_ = 0;
  148. if (is_open(impl))
  149. {
  150. BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
  151. &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
  152. HANDLE wait_handle = impl.wait_handle_;
  153. impl.wait_handle_ = INVALID_HANDLE_VALUE;
  154. op_queue<operation> ops;
  155. while (wait_op* op = impl.op_queue_.front())
  156. {
  157. op->ec_ = boost::asio::error::operation_aborted;
  158. impl.op_queue_.pop();
  159. ops.push(op);
  160. }
  161. // We must not hold the lock while calling UnregisterWaitEx. This is
  162. // because the registered callback function might be invoked while we are
  163. // waiting for UnregisterWaitEx to complete.
  164. lock.unlock();
  165. if (wait_handle != INVALID_HANDLE_VALUE)
  166. ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
  167. ::CloseHandle(impl.handle_);
  168. impl.handle_ = INVALID_HANDLE_VALUE;
  169. io_context_.post_deferred_completions(ops);
  170. }
  171. }
  172. boost::system::error_code win_object_handle_service::assign(
  173. win_object_handle_service::implementation_type& impl,
  174. const native_handle_type& handle, boost::system::error_code& ec)
  175. {
  176. if (is_open(impl))
  177. {
  178. ec = boost::asio::error::already_open;
  179. return ec;
  180. }
  181. impl.handle_ = handle;
  182. ec = boost::system::error_code();
  183. return ec;
  184. }
  185. boost::system::error_code win_object_handle_service::close(
  186. win_object_handle_service::implementation_type& impl,
  187. boost::system::error_code& ec)
  188. {
  189. if (is_open(impl))
  190. {
  191. BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
  192. &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
  193. mutex::scoped_lock lock(mutex_);
  194. HANDLE wait_handle = impl.wait_handle_;
  195. impl.wait_handle_ = INVALID_HANDLE_VALUE;
  196. op_queue<operation> completed_ops;
  197. while (wait_op* op = impl.op_queue_.front())
  198. {
  199. impl.op_queue_.pop();
  200. op->ec_ = boost::asio::error::operation_aborted;
  201. completed_ops.push(op);
  202. }
  203. // We must not hold the lock while calling UnregisterWaitEx. This is
  204. // because the registered callback function might be invoked while we are
  205. // waiting for UnregisterWaitEx to complete.
  206. lock.unlock();
  207. if (wait_handle != INVALID_HANDLE_VALUE)
  208. ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
  209. if (::CloseHandle(impl.handle_))
  210. {
  211. impl.handle_ = INVALID_HANDLE_VALUE;
  212. ec = boost::system::error_code();
  213. }
  214. else
  215. {
  216. DWORD last_error = ::GetLastError();
  217. ec = boost::system::error_code(last_error,
  218. boost::asio::error::get_system_category());
  219. }
  220. io_context_.post_deferred_completions(completed_ops);
  221. }
  222. else
  223. {
  224. ec = boost::system::error_code();
  225. }
  226. return ec;
  227. }
  228. boost::system::error_code win_object_handle_service::cancel(
  229. win_object_handle_service::implementation_type& impl,
  230. boost::system::error_code& ec)
  231. {
  232. if (is_open(impl))
  233. {
  234. BOOST_ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
  235. &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
  236. mutex::scoped_lock lock(mutex_);
  237. HANDLE wait_handle = impl.wait_handle_;
  238. impl.wait_handle_ = INVALID_HANDLE_VALUE;
  239. op_queue<operation> completed_ops;
  240. while (wait_op* op = impl.op_queue_.front())
  241. {
  242. op->ec_ = boost::asio::error::operation_aborted;
  243. impl.op_queue_.pop();
  244. completed_ops.push(op);
  245. }
  246. // We must not hold the lock while calling UnregisterWaitEx. This is
  247. // because the registered callback function might be invoked while we are
  248. // waiting for UnregisterWaitEx to complete.
  249. lock.unlock();
  250. if (wait_handle != INVALID_HANDLE_VALUE)
  251. ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
  252. ec = boost::system::error_code();
  253. io_context_.post_deferred_completions(completed_ops);
  254. }
  255. else
  256. {
  257. ec = boost::asio::error::bad_descriptor;
  258. }
  259. return ec;
  260. }
  261. void win_object_handle_service::wait(
  262. win_object_handle_service::implementation_type& impl,
  263. boost::system::error_code& ec)
  264. {
  265. switch (::WaitForSingleObject(impl.handle_, INFINITE))
  266. {
  267. case WAIT_FAILED:
  268. {
  269. DWORD last_error = ::GetLastError();
  270. ec = boost::system::error_code(last_error,
  271. boost::asio::error::get_system_category());
  272. break;
  273. }
  274. case WAIT_OBJECT_0:
  275. case WAIT_ABANDONED:
  276. default:
  277. ec = boost::system::error_code();
  278. break;
  279. }
  280. }
  281. void win_object_handle_service::start_wait_op(
  282. win_object_handle_service::implementation_type& impl, wait_op* op)
  283. {
  284. io_context_.work_started();
  285. if (is_open(impl))
  286. {
  287. mutex::scoped_lock lock(mutex_);
  288. if (!shutdown_)
  289. {
  290. impl.op_queue_.push(op);
  291. // Only the first operation to be queued gets to register a wait callback.
  292. // Subsequent operations have to wait for the first to finish.
  293. if (impl.op_queue_.front() == op)
  294. register_wait_callback(impl, lock);
  295. }
  296. else
  297. {
  298. lock.unlock();
  299. io_context_.post_deferred_completion(op);
  300. }
  301. }
  302. else
  303. {
  304. op->ec_ = boost::asio::error::bad_descriptor;
  305. io_context_.post_deferred_completion(op);
  306. }
  307. }
  308. void win_object_handle_service::register_wait_callback(
  309. win_object_handle_service::implementation_type& impl,
  310. mutex::scoped_lock& lock)
  311. {
  312. lock.lock();
  313. if (!RegisterWaitForSingleObject(&impl.wait_handle_,
  314. impl.handle_, &win_object_handle_service::wait_callback,
  315. &impl, INFINITE, WT_EXECUTEONLYONCE))
  316. {
  317. DWORD last_error = ::GetLastError();
  318. boost::system::error_code ec(last_error,
  319. boost::asio::error::get_system_category());
  320. op_queue<operation> completed_ops;
  321. while (wait_op* op = impl.op_queue_.front())
  322. {
  323. op->ec_ = ec;
  324. impl.op_queue_.pop();
  325. completed_ops.push(op);
  326. }
  327. lock.unlock();
  328. io_context_.post_deferred_completions(completed_ops);
  329. }
  330. }
  331. void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
  332. {
  333. implementation_type* impl = static_cast<implementation_type*>(param);
  334. mutex::scoped_lock lock(impl->owner_->mutex_);
  335. if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
  336. {
  337. ::UnregisterWaitEx(impl->wait_handle_, NULL);
  338. impl->wait_handle_ = INVALID_HANDLE_VALUE;
  339. }
  340. if (wait_op* op = impl->op_queue_.front())
  341. {
  342. op_queue<operation> completed_ops;
  343. op->ec_ = boost::system::error_code();
  344. impl->op_queue_.pop();
  345. completed_ops.push(op);
  346. if (!impl->op_queue_.empty())
  347. {
  348. if (!RegisterWaitForSingleObject(&impl->wait_handle_,
  349. impl->handle_, &win_object_handle_service::wait_callback,
  350. param, INFINITE, WT_EXECUTEONLYONCE))
  351. {
  352. DWORD last_error = ::GetLastError();
  353. boost::system::error_code ec(last_error,
  354. boost::asio::error::get_system_category());
  355. while ((op = impl->op_queue_.front()) != 0)
  356. {
  357. op->ec_ = ec;
  358. impl->op_queue_.pop();
  359. completed_ops.push(op);
  360. }
  361. }
  362. }
  363. io_context_impl& ioc = impl->owner_->io_context_;
  364. lock.unlock();
  365. ioc.post_deferred_completions(completed_ops);
  366. }
  367. }
  368. } // namespace detail
  369. } // namespace asio
  370. } // namespace boost
  371. #include <boost/asio/detail/pop_options.hpp>
  372. #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE)
  373. #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP