winrt_async_manager.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. //
  2. // detail/winrt_async_manager.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2021 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_WINRT_ASYNC_MANAGER_HPP
  11. #define BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_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/config.hpp>
  16. #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
  17. #include <future>
  18. #include <boost/asio/detail/atomic_count.hpp>
  19. #include <boost/asio/detail/winrt_async_op.hpp>
  20. #include <boost/asio/error.hpp>
  21. #include <boost/asio/execution_context.hpp>
  22. #if defined(BOOST_ASIO_HAS_IOCP)
  23. # include <boost/asio/detail/win_iocp_io_context.hpp>
  24. #else // defined(BOOST_ASIO_HAS_IOCP)
  25. # include <boost/asio/detail/scheduler.hpp>
  26. #endif // defined(BOOST_ASIO_HAS_IOCP)
  27. #include <boost/asio/detail/push_options.hpp>
  28. namespace boost {
  29. namespace asio {
  30. namespace detail {
  31. class winrt_async_manager
  32. : public execution_context_service_base<winrt_async_manager>
  33. {
  34. public:
  35. // Constructor.
  36. winrt_async_manager(execution_context& context)
  37. : execution_context_service_base<winrt_async_manager>(context),
  38. scheduler_(use_service<scheduler_impl>(context)),
  39. outstanding_ops_(1)
  40. {
  41. }
  42. // Destructor.
  43. ~winrt_async_manager()
  44. {
  45. }
  46. // Destroy all user-defined handler objects owned by the service.
  47. void shutdown()
  48. {
  49. if (--outstanding_ops_ > 0)
  50. {
  51. // Block until last operation is complete.
  52. std::future<void> f = promise_.get_future();
  53. f.wait();
  54. }
  55. }
  56. void sync(Windows::Foundation::IAsyncAction^ action,
  57. boost::system::error_code& ec)
  58. {
  59. using namespace Windows::Foundation;
  60. using Windows::Foundation::AsyncStatus;
  61. auto promise = std::make_shared<std::promise<boost::system::error_code>>();
  62. auto future = promise->get_future();
  63. action->Completed = ref new AsyncActionCompletedHandler(
  64. [promise](IAsyncAction^ action, AsyncStatus status)
  65. {
  66. switch (status)
  67. {
  68. case AsyncStatus::Canceled:
  69. promise->set_value(boost::asio::error::operation_aborted);
  70. break;
  71. case AsyncStatus::Error:
  72. case AsyncStatus::Completed:
  73. default:
  74. boost::system::error_code ec(
  75. action->ErrorCode.Value,
  76. boost::system::system_category());
  77. promise->set_value(ec);
  78. break;
  79. }
  80. });
  81. ec = future.get();
  82. }
  83. template <typename TResult>
  84. TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation,
  85. boost::system::error_code& ec)
  86. {
  87. using namespace Windows::Foundation;
  88. using Windows::Foundation::AsyncStatus;
  89. auto promise = std::make_shared<std::promise<boost::system::error_code>>();
  90. auto future = promise->get_future();
  91. operation->Completed = ref new AsyncOperationCompletedHandler<TResult>(
  92. [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status)
  93. {
  94. switch (status)
  95. {
  96. case AsyncStatus::Canceled:
  97. promise->set_value(boost::asio::error::operation_aborted);
  98. break;
  99. case AsyncStatus::Error:
  100. case AsyncStatus::Completed:
  101. default:
  102. boost::system::error_code ec(
  103. operation->ErrorCode.Value,
  104. boost::system::system_category());
  105. promise->set_value(ec);
  106. break;
  107. }
  108. });
  109. ec = future.get();
  110. return operation->GetResults();
  111. }
  112. template <typename TResult, typename TProgress>
  113. TResult sync(
  114. Windows::Foundation::IAsyncOperationWithProgress<
  115. TResult, TProgress>^ operation,
  116. boost::system::error_code& ec)
  117. {
  118. using namespace Windows::Foundation;
  119. using Windows::Foundation::AsyncStatus;
  120. auto promise = std::make_shared<std::promise<boost::system::error_code>>();
  121. auto future = promise->get_future();
  122. operation->Completed
  123. = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
  124. [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation,
  125. AsyncStatus status)
  126. {
  127. switch (status)
  128. {
  129. case AsyncStatus::Canceled:
  130. promise->set_value(boost::asio::error::operation_aborted);
  131. break;
  132. case AsyncStatus::Started:
  133. break;
  134. case AsyncStatus::Error:
  135. case AsyncStatus::Completed:
  136. default:
  137. boost::system::error_code ec(
  138. operation->ErrorCode.Value,
  139. boost::system::system_category());
  140. promise->set_value(ec);
  141. break;
  142. }
  143. });
  144. ec = future.get();
  145. return operation->GetResults();
  146. }
  147. void async(Windows::Foundation::IAsyncAction^ action,
  148. winrt_async_op<void>* handler)
  149. {
  150. using namespace Windows::Foundation;
  151. using Windows::Foundation::AsyncStatus;
  152. auto on_completed = ref new AsyncActionCompletedHandler(
  153. [this, handler](IAsyncAction^ action, AsyncStatus status)
  154. {
  155. switch (status)
  156. {
  157. case AsyncStatus::Canceled:
  158. handler->ec_ = boost::asio::error::operation_aborted;
  159. break;
  160. case AsyncStatus::Started:
  161. return;
  162. case AsyncStatus::Completed:
  163. case AsyncStatus::Error:
  164. default:
  165. handler->ec_ = boost::system::error_code(
  166. action->ErrorCode.Value,
  167. boost::system::system_category());
  168. break;
  169. }
  170. scheduler_.post_deferred_completion(handler);
  171. if (--outstanding_ops_ == 0)
  172. promise_.set_value();
  173. });
  174. scheduler_.work_started();
  175. ++outstanding_ops_;
  176. action->Completed = on_completed;
  177. }
  178. template <typename TResult>
  179. void async(Windows::Foundation::IAsyncOperation<TResult>^ operation,
  180. winrt_async_op<TResult>* handler)
  181. {
  182. using namespace Windows::Foundation;
  183. using Windows::Foundation::AsyncStatus;
  184. auto on_completed = ref new AsyncOperationCompletedHandler<TResult>(
  185. [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status)
  186. {
  187. switch (status)
  188. {
  189. case AsyncStatus::Canceled:
  190. handler->ec_ = boost::asio::error::operation_aborted;
  191. break;
  192. case AsyncStatus::Started:
  193. return;
  194. case AsyncStatus::Completed:
  195. handler->result_ = operation->GetResults();
  196. // Fall through.
  197. case AsyncStatus::Error:
  198. default:
  199. handler->ec_ = boost::system::error_code(
  200. operation->ErrorCode.Value,
  201. boost::system::system_category());
  202. break;
  203. }
  204. scheduler_.post_deferred_completion(handler);
  205. if (--outstanding_ops_ == 0)
  206. promise_.set_value();
  207. });
  208. scheduler_.work_started();
  209. ++outstanding_ops_;
  210. operation->Completed = on_completed;
  211. }
  212. template <typename TResult, typename TProgress>
  213. void async(
  214. Windows::Foundation::IAsyncOperationWithProgress<
  215. TResult, TProgress>^ operation,
  216. winrt_async_op<TResult>* handler)
  217. {
  218. using namespace Windows::Foundation;
  219. using Windows::Foundation::AsyncStatus;
  220. auto on_completed
  221. = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
  222. [this, handler](IAsyncOperationWithProgress<
  223. TResult, TProgress>^ operation, AsyncStatus status)
  224. {
  225. switch (status)
  226. {
  227. case AsyncStatus::Canceled:
  228. handler->ec_ = boost::asio::error::operation_aborted;
  229. break;
  230. case AsyncStatus::Started:
  231. return;
  232. case AsyncStatus::Completed:
  233. handler->result_ = operation->GetResults();
  234. // Fall through.
  235. case AsyncStatus::Error:
  236. default:
  237. handler->ec_ = boost::system::error_code(
  238. operation->ErrorCode.Value,
  239. boost::system::system_category());
  240. break;
  241. }
  242. scheduler_.post_deferred_completion(handler);
  243. if (--outstanding_ops_ == 0)
  244. promise_.set_value();
  245. });
  246. scheduler_.work_started();
  247. ++outstanding_ops_;
  248. operation->Completed = on_completed;
  249. }
  250. private:
  251. // The scheduler implementation used to post completed handlers.
  252. #if defined(BOOST_ASIO_HAS_IOCP)
  253. typedef class win_iocp_io_context scheduler_impl;
  254. #else
  255. typedef class scheduler scheduler_impl;
  256. #endif
  257. scheduler_impl& scheduler_;
  258. // Count of outstanding operations.
  259. atomic_count outstanding_ops_;
  260. // Used to keep wait for outstanding operations to complete.
  261. std::promise<void> promise_;
  262. };
  263. } // namespace detail
  264. } // namespace asio
  265. } // namespace boost
  266. #include <boost/asio/detail/pop_options.hpp>
  267. #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
  268. #endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP