win_object_handle_service.ipp 12 KB

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