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