1 /*** 2 * ==++== 3 * 4 * Copyright (c) Microsoft Corporation. All rights reserved. 5 * 6 * Modified for native C++ WRL support by Gregory Morse 7 * 8 * ==--== 9 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 10 * 11 * ppltasks_winrt.h 12 * 13 * Parallel Patterns Library - PPL Tasks 14 * 15 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 16 ****/ 17 18 #pragma once 19 20 #ifndef _PPLTASKS_WINRT_H 21 #define _PPLTASKS_WINRT_H 22 23 #include <concrt.h> 24 #include <ppltasks.h> 25 #if _MSC_VER >= 1800 26 #include <pplconcrt.h> 27 28 // Cannot build using a compiler that is older than dev10 SP1 29 #ifdef _MSC_VER 30 #if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/ 31 #error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks 32 #endif /*IFSTRIP=IGN*/ 33 #endif 34 #else 35 #include <ppl.h> 36 #endif 37 #include <functional> 38 #include <vector> 39 #include <utility> 40 #include <exception> 41 #if _MSC_VER >= 1800 42 #include <algorithm> 43 #endif 44 45 #ifndef __cplusplus_winrt 46 47 #include <wrl\implements.h> 48 #include <wrl\async.h> 49 #if _MSC_VER >= 1800 50 #include "agile_wrl.h" 51 #endif 52 #include <windows.foundation.h> 53 #include <ctxtcall.h> 54 55 #ifndef _UITHREADCTXT_SUPPORT 56 57 #ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/ 58 59 // It is safe to include winapifamily as WINAPI_FAMILY was defined by the user 60 #include <winapifamily.h> 61 62 #if WINAPI_FAMILY == WINAPI_FAMILY_APP /*IFSTRIP=IGN*/ 63 // UI thread context support is not required for desktop and Windows Store apps 64 #define _UITHREADCTXT_SUPPORT 0 65 #elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP /*IFSTRIP=IGN*/ 66 // UI thread context support is not required for desktop and Windows Store apps 67 #define _UITHREADCTXT_SUPPORT 0 68 #else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ 69 #define _UITHREADCTXT_SUPPORT 1 70 #endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */ 71 72 #else /* WINAPI_FAMILY */ 73 // Not supported without a WINAPI_FAMILY setting. 74 #define _UITHREADCTXT_SUPPORT 0 75 #endif /* WINAPI_FAMILY */ 76 77 #endif /* _UITHREADCTXT_SUPPORT */ 78 79 #if _UITHREADCTXT_SUPPORT 80 #include <uithreadctxt.h> 81 #endif /* _UITHREADCTXT_SUPPORT */ 82 83 #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0") 84 85 #ifdef _DEBUG 86 #define _DBG_ONLY(X) X 87 #else 88 #define _DBG_ONLY(X) 89 #endif // #ifdef _DEBUG 90 91 // std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11. 92 #ifdef _MSC_VER 93 #if _MSC_VER < 1700 /*IFSTRIP=IGN*/ 94 namespace std 95 { 96 template<class _E> exception_ptr make_exception_ptr(_E _Except) 97 { 98 return copy_exception(_Except); 99 } 100 } 101 #endif 102 #ifndef _PPLTASK_ASYNC_LOGGING 103 #if _MSC_VER >= 1800 && defined(__cplusplus_winrt) 104 #define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt 105 #else 106 #define _PPLTASK_ASYNC_LOGGING 0 107 #endif 108 #endif 109 #endif 110 111 #pragma pack(push,_CRT_PACKING) 112 113 #pragma warning(push) 114 #pragma warning(disable: 28197) 115 #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation 116 #if _MSC_VER >= 1800 117 #pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming 118 #else 119 #pragma warning(disable: 4702) // Unreachable code - it is caused by user lambda throw exceptions 120 #endif 121 122 // All CRT public header files are required to be protected from the macro new 123 #pragma push_macro("new") 124 #undef new 125 126 // stuff ported from Dev11 CRT 127 // NOTE: this doesn't actually match std::declval. it behaves differently for void! 128 // so don't blindly change it to std::declval. 129 namespace stdx 130 { 131 template<class _T> 132 _T&& declval(); 133 } 134 135 /// <summary> 136 /// The <c>Concurrency_winrt</c> namespace provides classes and functions that give you access to the Concurrency Runtime, 137 /// a concurrent programming framework for C++. For more information, see <see cref="Concurrency Runtime"/>. 138 /// </summary> 139 /**/ 140 namespace Concurrency_winrt 141 { 142 // In debug builds, default to 10 frames, unless this is overridden prior to #includ'ing ppltasks.h. In retail builds, default to only one frame. 143 #ifndef PPL_TASK_SAVE_FRAME_COUNT 144 #ifdef _DEBUG 145 #define PPL_TASK_SAVE_FRAME_COUNT 10 146 #else 147 #define PPL_TASK_SAVE_FRAME_COUNT 1 148 #endif 149 #endif 150 151 /// <summary> 152 /// Helper macro to determine how many stack frames need to be saved. When any number less or equal to 1 is specified, 153 /// only one frame is captured and no stackwalk will be involved. Otherwise, the number of callstack frames will be captured. 154 /// </summary> 155 /// <ramarks> 156 /// This needs to be defined as a macro rather than a function so that if we're only gathering one frame, _ReturnAddress() 157 /// will evaluate to client code, rather than a helper function inside of _TaskCreationCallstack, itself. 158 /// </remarks> 159 #ifdef _CAPTURE_CALLSTACK 160 #undef _CAPTURE_CALLSTACK 161 #endif 162 #if PPL_TASK_SAVE_FRAME_COUNT > 1 163 #if !defined(_DEBUG) 164 #pragma message ("WARNING: Redefinning PPL_TASK_SAVE_FRAME_COUNT under Release build for non-desktop applications is not supported; only one frame will be captured!") 165 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) 166 #else 167 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT) 168 #endif 169 #else 170 #define _CAPTURE_CALLSTACK() ::Concurrency_winrt::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress()) 171 #endif 172 /// <summary> 173 174 /// A type that represents the terminal state of a task. Valid values are <c>completed</c> and <c>canceled</c>. 175 /// </summary> 176 /// <seealso cref="task Class"/> 177 /**/ 178 typedef Concurrency::task_group_status task_status; 179 180 template <typename _Type> class task; 181 template <> class task<void>; 182 183 /// <summary> 184 /// Returns an indication of whether the task that is currently executing has received a request to cancel its 185 /// execution. Cancellation is requested on a task if the task was created with a cancellation token, and 186 /// the token source associated with that token is canceled. 187 /// </summary> 188 /// <returns> 189 /// <c>true</c> if the currently executing task has received a request for cancellation, <c>false</c> otherwise. 190 /// </returns> 191 /// <remarks> 192 /// If you call this method in the body of a task and it returns <c>true</c>, you must respond with a call to 193 /// <see cref="cancel_current_task Function">cancel_current_task</see> to acknowledge the cancellation request, 194 /// after performing any cleanup you need. This will abort the execution of the task and cause it to enter into 195 /// the <c>canceled</c> state. If you do not respond and continue execution, or return instead of calling 196 /// <c>cancel_current_task</c>, the task will enter the <c>completed</c> state when it is done. 197 /// state. 198 /// <para>A task is not cancellable if it was created without a cancellation token.</para> 199 /// </remarks> 200 /// <seealso cref="task Class"/> 201 /// <seealso cref="cancellation_token_source Class"/> 202 /// <seealso cref="cancellation_token Class"/> 203 /// <seealso cref="cancel_current_task Function"/> 204 /**/ 205 #if _MSC_VER >= 1800 206 inline bool __cdecl is_task_cancellation_requested() 207 { 208 return ::Concurrency::details::_TaskCollection_t::_Is_cancellation_requested(); 209 } 210 #else 211 inline bool __cdecl is_task_cancellation_requested() 212 { 213 // ConcRT scheduler under the hood is using TaskCollection, which is same as task_group 214 return ::Concurrency::is_current_task_group_canceling(); 215 } 216 #endif 217 218 /// <summary> 219 /// Cancels the currently executing task. This function can be called from within the body of a task to abort the 220 /// task's execution and cause it to enter the <c>canceled</c> state. While it may be used in response to 221 /// the <see cref="is_task_cancellation_requested Function">is_task_cancellation_requested</see> function, you may 222 /// also use it by itself, to initiate cancellation of the task that is currently executing. 223 /// <para>It is not a supported scenario to call this function if you are not within the body of a <c>task</c>. 224 /// Doing so will result in undefined behavior such as a crash or a hang in your application.</para> 225 /// </summary> 226 /// <seealso cref="task Class"/> 227 /// <seealso cref="is_task_cancellation_requested"/> 228 /**/ 229 //#if _MSC_VER >= 1800 230 inline __declspec(noreturn) void __cdecl cancel_current_task() 231 { 232 throw Concurrency::task_canceled(); 233 } 234 //#else 235 //_CRTIMP2 __declspec(noreturn) void __cdecl cancel_current_task(); 236 //#endif 237 238 namespace details 239 { 240 #if _MSC_VER >= 1800 241 /// <summary> 242 /// Callstack container, which is used to capture and preserve callstacks in ppltasks. 243 /// Members of this class is examined by vc debugger, thus there will be no public access methods. 244 /// Please note that names of this class should be kept stable for debugger examining. 245 /// </summary> 246 class _TaskCreationCallstack 247 { 248 private: 249 // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame; 250 // otherwise, _M_Frame will store all the callstack frames. 251 void* _M_SingleFrame; 252 std::vector<void *> _M_frames; 253 public: 254 _TaskCreationCallstack() 255 { 256 _M_SingleFrame = nullptr; 257 } 258 259 // Store one frame of callstack. This function works for both Debug / Release CRT. 260 static _TaskCreationCallstack _CaptureSingleFrameCallstack(void *_SingleFrame) 261 { 262 _TaskCreationCallstack _csc; 263 _csc._M_SingleFrame = _SingleFrame; 264 return _csc; 265 } 266 267 // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT. 268 __declspec(noinline) 269 static _TaskCreationCallstack _CaptureMultiFramesCallstack(size_t _CaptureFrames) 270 { 271 _TaskCreationCallstack _csc; 272 _csc._M_frames.resize(_CaptureFrames); 273 // skip 2 frames to make sure callstack starts from user code 274 _csc._M_frames.resize(::Concurrency::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames)); 275 return _csc; 276 } 277 }; 278 #endif 279 typedef UINT32 _Unit_type; 280 281 struct _TypeSelectorNoAsync {}; 282 struct _TypeSelectorAsyncOperationOrTask {}; 283 struct _TypeSelectorAsyncOperation : public _TypeSelectorAsyncOperationOrTask { }; 284 struct _TypeSelectorAsyncTask : public _TypeSelectorAsyncOperationOrTask { }; 285 struct _TypeSelectorAsyncAction {}; 286 struct _TypeSelectorAsyncActionWithProgress {}; 287 struct _TypeSelectorAsyncOperationWithProgress {}; 288 289 template<typename _Ty> 290 struct _NormalizeVoidToUnitType 291 { 292 typedef _Ty _Type; 293 }; 294 295 template<> 296 struct _NormalizeVoidToUnitType<void> 297 { 298 typedef _Unit_type _Type; 299 }; 300 301 template<typename _T> 302 struct _IsUnwrappedAsyncSelector 303 { 304 static const bool _Value = true; 305 }; 306 307 template<> 308 struct _IsUnwrappedAsyncSelector<_TypeSelectorNoAsync> 309 { 310 static const bool _Value = false; 311 }; 312 313 template <typename _Ty> 314 struct _UnwrapTaskType 315 { 316 typedef _Ty _Type; 317 }; 318 319 template <typename _Ty> 320 struct _UnwrapTaskType<task<_Ty>> 321 { 322 typedef _Ty _Type; 323 }; 324 325 template <typename _T> 326 _TypeSelectorAsyncTask _AsyncOperationKindSelector(task<_T>); 327 328 _TypeSelectorNoAsync _AsyncOperationKindSelector(...); 329 330 template <typename _Type> 331 struct _Unhat 332 { 333 typedef _Type _Value; 334 }; 335 336 template <typename _Type> 337 struct _Unhat<_Type*> 338 { 339 typedef _Type _Value; 340 }; 341 342 //struct _NonUserType { public: int _Dummy; }; 343 344 template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)> 345 struct _ValueTypeOrRefType 346 { 347 typedef _Unit_type _Value; 348 }; 349 350 template <typename _Type> 351 struct _ValueTypeOrRefType<_Type, true> 352 { 353 typedef _Type _Value; 354 }; 355 356 template <typename _Ty> 357 _Ty _UnwrapAsyncActionWithProgressSelector(ABI::Windows::Foundation::IAsyncActionWithProgress_impl<_Ty>*); 358 359 template <typename _Ty> 360 _Ty _UnwrapAsyncActionWithProgressSelector(...); 361 362 template <typename _Ty, typename _Progress> 363 _Progress _UnwrapAsyncOperationWithProgressProgressSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress_impl<_Ty, _Progress>*); 364 365 template <typename _Ty, typename _Progress> 366 _Progress _UnwrapAsyncOperationWithProgressProgressSelector(...); 367 368 template <typename _T1, typename _T2> 369 _T2 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*); 370 371 template <typename _T1> 372 _T1 _ProgressTypeSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T1>*); 373 374 template <typename _Type> 375 struct _GetProgressType 376 { 377 typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value; 378 }; 379 380 template <typename _T> 381 _TypeSelectorAsyncOperation _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*); 382 383 _TypeSelectorAsyncAction _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*); 384 385 template <typename _T1, typename _T2> 386 _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*); 387 388 template <typename _T> 389 _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*); 390 391 template <typename _Type> 392 struct _IsIAsyncInfo 393 { 394 static const bool _Value = std::is_base_of<ABI::Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value>::value || 395 std::is_same<_TypeSelectorAsyncAction, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value || 396 std::is_same<_TypeSelectorAsyncOperation, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value || 397 std::is_same<_TypeSelectorAsyncOperationWithProgress, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value || 398 std::is_same<_TypeSelectorAsyncActionWithProgress, decltype(details::_AsyncOperationKindSelector(stdx::declval<_Type>()))>::value; 399 }; 400 401 template <> 402 struct _IsIAsyncInfo<void> 403 { 404 static const bool _Value = false; 405 }; 406 407 template <typename _Ty> 408 _Ty _UnwrapAsyncOperationSelector(ABI::Windows::Foundation::IAsyncOperation_impl<_Ty>*); 409 410 template <typename _Ty> 411 _Ty _UnwrapAsyncOperationSelector(...); 412 413 template <typename _Ty, typename _Progress> 414 _Ty _UnwrapAsyncOperationWithProgressSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress_impl<_Ty, _Progress>*); 415 416 template <typename _Ty, typename _Progress> 417 _Ty _UnwrapAsyncOperationWithProgressSelector(...); 418 419 // Unwrap functions for asyncOperations 420 template<typename _Ty> 421 auto _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperation<_Ty>*) -> typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Ty>*>()))>::type; 422 423 void _GetUnwrappedType(ABI::Windows::Foundation::IAsyncAction*); 424 425 template<typename _Ty, typename _Progress> 426 auto _GetUnwrappedType(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>*) -> typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>*>()))>::type; 427 428 template<typename _Progress> 429 void _GetUnwrappedType(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>*); 430 431 template <typename _T> 432 _T _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperation<_T>*); 433 434 void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncAction*); 435 436 template <typename _T1, typename _T2> 437 _T1 _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>*); 438 439 template <typename _T> 440 void _ReturnAsyncOperationKindSelector(ABI::Windows::Foundation::IAsyncActionWithProgress<_T>*); 441 442 class _ProgressReporterCtorArgType{}; 443 444 template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value> 445 struct _TaskTypeTraits 446 { 447 typedef typename details::_UnwrapTaskType<_Type>::_Type _TaskRetType; 448 typedef _TaskRetType _TaskRetType_abi; 449 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; 450 typedef typename details::_NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType; 451 452 static const bool _IsAsyncTask = _IsAsync; 453 static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value; 454 }; 455 456 template<typename _Type> 457 struct _TaskTypeTraits<_Type, true> 458 { 459 typedef decltype(_ReturnAsyncOperationKindSelector(stdx::declval<_Type>())) _TaskRetType; 460 typedef decltype(_GetUnwrappedType(stdx::declval<_Type>())) _TaskRetType_abi; 461 typedef _TaskRetType _NormalizedTaskRetType; 462 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind; 463 464 static const bool _IsAsyncTask = true; 465 static const bool _IsUnwrappedTaskOrAsync = details::_IsUnwrappedAsyncSelector<_AsyncKind>::_Value; 466 }; 467 468 template <typename _ReturnType, typename _Function> auto _IsCallable(_Function _Func, int, int, int) -> decltype(_Func(stdx::declval<task<_ReturnType>*>()), std::true_type()) { (void)_Func; return std::true_type(); } 469 template <typename _ReturnType, typename _Function> auto _IsCallable(_Function _Func, int, int, ...) -> decltype(_Func(stdx::declval<_ReturnType*>()), std::true_type()) { (void)_Func; return std::true_type(); } 470 template <typename _ReturnType, typename _Function> auto _IsCallable(_Function _Func, int, ...) -> decltype(_Func(), std::true_type()) { (void)_Func; return std::true_type(); } 471 template <typename _ReturnType, typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); } 472 473 template <> 474 struct _TaskTypeTraits<void> 475 { 476 typedef void _TaskRetType; 477 typedef void _TaskRetType_abi; 478 typedef _TypeSelectorNoAsync _AsyncKind; 479 typedef _Unit_type _NormalizedTaskRetType; 480 481 static const bool _IsAsyncTask = false; 482 static const bool _IsUnwrappedTaskOrAsync = false; 483 }; 484 485 // *************************************************************************** 486 // Template type traits and helpers for async production APIs: 487 // 488 489 struct _ZeroArgumentFunctor { }; 490 struct _OneArgumentFunctor { }; 491 struct _TwoArgumentFunctor { }; 492 struct _ThreeArgumentFunctor { }; 493 494 // **************************************** 495 // CLASS TYPES: 496 497 // mutable functions 498 // ******************** 499 // THREE ARGUMENTS: 500 501 // non-void arg: 502 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 503 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3)); 504 505 // non-void arg: 506 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 507 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3)); 508 509 // non-void arg: 510 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 511 _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3)); 512 513 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 514 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3)); 515 516 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 517 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3)); 518 519 // ******************** 520 // TWO ARGUMENTS: 521 522 // non-void arg: 523 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 524 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2)); 525 526 // non-void arg: 527 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 528 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2)); 529 530 // non-void arg: 531 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 532 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2)); 533 534 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 535 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2)); 536 537 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 538 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2)); 539 540 // ******************** 541 // ONE ARGUMENT: 542 543 // non-void arg: 544 template<typename _Class, typename _ReturnType, typename _Arg1> 545 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1)); 546 547 // non-void arg: 548 template<typename _Class, typename _ReturnType, typename _Arg1> 549 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1)); 550 551 // non-void arg: 552 template<typename _Class, typename _ReturnType, typename _Arg1> 553 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1)); 554 555 template<typename _Class, typename _ReturnType, typename _Arg1> 556 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1)); 557 558 template<typename _Class, typename _ReturnType, typename _Arg1> 559 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1)); 560 561 // ******************** 562 // ZERO ARGUMENT: 563 564 // void arg: 565 template<typename _Class, typename _ReturnType> 566 void _Arg1ClassHelperThunk(_ReturnType(_Class::*)()); 567 568 // void arg: 569 template<typename _Class, typename _ReturnType> 570 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)()); 571 572 // void arg: 573 template<typename _Class, typename _ReturnType> 574 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)()); 575 576 // void arg: 577 template<typename _Class, typename _ReturnType> 578 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)()); 579 580 template<typename _Class, typename _ReturnType> 581 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)()); 582 583 // ******************** 584 // THREE ARGUMENTS: 585 586 // non-void arg: 587 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 588 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const); 589 590 // non-void arg: 591 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 592 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const); 593 594 // non-void arg: 595 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 596 _Arg3 _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const); 597 598 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 599 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const); 600 601 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 602 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2, _Arg3) const); 603 604 // ******************** 605 // TWO ARGUMENTS: 606 607 // non-void arg: 608 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 609 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const); 610 611 // non-void arg: 612 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 613 _Arg2 _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const); 614 615 // non-void arg: 616 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 617 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const); 618 619 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 620 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1, _Arg2) const); 621 622 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2> 623 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1, _Arg2) const); 624 625 // ******************** 626 // ONE ARGUMENT: 627 628 // non-void arg: 629 template<typename _Class, typename _ReturnType, typename _Arg1> 630 _Arg1 _Arg1ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const); 631 632 // non-void arg: 633 template<typename _Class, typename _ReturnType, typename _Arg1> 634 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const); 635 636 // non-void arg: 637 template<typename _Class, typename _ReturnType, typename _Arg1> 638 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const); 639 640 template<typename _Class, typename _ReturnType, typename _Arg1> 641 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)(_Arg1) const); 642 643 template<typename _Class, typename _ReturnType, typename _Arg1> 644 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)(_Arg1) const); 645 646 // ******************** 647 // ZERO ARGUMENT: 648 649 // void arg: 650 template<typename _Class, typename _ReturnType> 651 void _Arg1ClassHelperThunk(_ReturnType(_Class::*)() const); 652 653 // void arg: 654 template<typename _Class, typename _ReturnType> 655 void _Arg2ClassHelperThunk(_ReturnType(_Class::*)() const); 656 657 // void arg: 658 template<typename _Class, typename _ReturnType> 659 void _Arg3ClassHelperThunk(_ReturnType(_Class::*)() const); 660 661 // void arg: 662 template<typename _Class, typename _ReturnType> 663 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType(_Class::*)() const); 664 665 template<typename _Class, typename _ReturnType> 666 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(_Class::*)() const); 667 668 // **************************************** 669 // POINTER TYPES: 670 671 // ******************** 672 // THREE ARGUMENTS: 673 674 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 675 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3)); 676 677 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 678 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3)); 679 680 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 681 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3)); 682 683 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 684 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3)); 685 686 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 687 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2, _Arg3)); 688 689 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 690 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3)); 691 692 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 693 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3)); 694 695 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 696 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3)); 697 698 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 699 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3)); 700 701 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 702 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2, _Arg3)); 703 704 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 705 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3)); 706 707 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 708 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3)); 709 710 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 711 _Arg3 _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3)); 712 713 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 714 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3)); 715 716 template<typename _ReturnType, typename _Arg1, typename _Arg2, typename _Arg3> 717 _ThreeArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2, _Arg3)); 718 719 // ******************** 720 // TWO ARGUMENTS: 721 722 template<typename _ReturnType, typename _Arg1, typename _Arg2> 723 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); 724 725 template<typename _ReturnType, typename _Arg1, typename _Arg2> 726 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); 727 728 template<typename _ReturnType, typename _Arg1, typename _Arg2> 729 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); 730 731 template<typename _ReturnType, typename _Arg1, typename _Arg2> 732 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2)); 733 734 template<typename _ReturnType, typename _Arg1, typename _Arg2> 735 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2)); 736 737 template<typename _ReturnType, typename _Arg1, typename _Arg2> 738 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); 739 740 template<typename _ReturnType, typename _Arg1, typename _Arg2> 741 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); 742 743 template<typename _ReturnType, typename _Arg1, typename _Arg2> 744 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); 745 746 template<typename _ReturnType, typename _Arg1, typename _Arg2> 747 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2)); 748 749 template<typename _ReturnType, typename _Arg1, typename _Arg2> 750 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2)); 751 752 template<typename _ReturnType, typename _Arg1, typename _Arg2> 753 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); 754 755 template<typename _ReturnType, typename _Arg1, typename _Arg2> 756 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); 757 758 template<typename _ReturnType, typename _Arg1, typename _Arg2> 759 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); 760 761 template<typename _ReturnType, typename _Arg1, typename _Arg2> 762 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2)); 763 764 template<typename _ReturnType, typename _Arg1, typename _Arg2> 765 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2)); 766 767 // ******************** 768 // ONE ARGUMENT: 769 770 template<typename _ReturnType, typename _Arg1> 771 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); 772 773 template<typename _ReturnType, typename _Arg1> 774 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); 775 776 template<typename _ReturnType, typename _Arg1> 777 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); 778 779 template<typename _ReturnType, typename _Arg1> 780 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1)); 781 782 template<typename _ReturnType, typename _Arg1> 783 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1)); 784 785 template<typename _ReturnType, typename _Arg1> 786 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); 787 788 template<typename _ReturnType, typename _Arg1> 789 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); 790 791 template<typename _ReturnType, typename _Arg1> 792 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); 793 794 template<typename _ReturnType, typename _Arg1> 795 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1)); 796 797 template<typename _ReturnType, typename _Arg1> 798 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1)); 799 800 template<typename _ReturnType, typename _Arg1> 801 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); 802 803 template<typename _ReturnType, typename _Arg1> 804 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); 805 806 template<typename _ReturnType, typename _Arg1> 807 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); 808 809 template<typename _ReturnType, typename _Arg1> 810 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1)); 811 812 template<typename _ReturnType, typename _Arg1> 813 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1)); 814 815 // ******************** 816 // ZERO ARGUMENT: 817 818 template<typename _ReturnType> 819 void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)()); 820 821 template<typename _ReturnType> 822 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)()); 823 824 template<typename _ReturnType> 825 void _Arg3PFNHelperThunk(_ReturnType(__cdecl *)()); 826 827 template<typename _ReturnType> 828 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)()); 829 830 template<typename _ReturnType> 831 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)()); 832 833 template<typename _ReturnType> 834 void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)()); 835 836 template<typename _ReturnType> 837 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)()); 838 839 template<typename _ReturnType> 840 void _Arg3PFNHelperThunk(_ReturnType(__stdcall *)()); 841 842 template<typename _ReturnType> 843 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)()); 844 845 template<typename _ReturnType> 846 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)()); 847 848 template<typename _ReturnType> 849 void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)()); 850 851 template<typename _ReturnType> 852 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)()); 853 854 template<typename _ReturnType> 855 void _Arg3PFNHelperThunk(_ReturnType(__fastcall *)()); 856 857 template<typename _ReturnType> 858 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)()); 859 860 template<typename _ReturnType> 861 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)()); 862 863 template<typename _T> 864 struct _FunctorArguments 865 { 866 static const size_t _Count = 0; 867 }; 868 869 template<> 870 struct _FunctorArguments<_OneArgumentFunctor> 871 { 872 static const size_t _Count = 1; 873 }; 874 875 template<> 876 struct _FunctorArguments<_TwoArgumentFunctor> 877 { 878 static const size_t _Count = 2; 879 }; 880 881 template<> 882 struct _FunctorArguments<_ThreeArgumentFunctor> 883 { 884 static const size_t _Count = 3; 885 }; 886 887 template<typename _T> 888 struct _FunctorTypeTraits 889 { 890 typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType; 891 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; 892 893 typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType; 894 typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type; 895 typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type; 896 typedef decltype(_Arg3ClassHelperThunk(&(_T::operator()))) _Argument3Type; 897 }; 898 899 template<typename _T> 900 struct _FunctorTypeTraits<_T *> 901 { 902 typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType; 903 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count; 904 905 typedef decltype(_ReturnTypePFNHelperThunk(stdx::declval<_T*>())) _ReturnType; 906 typedef decltype(_Arg1PFNHelperThunk(stdx::declval<_T*>())) _Argument1Type; 907 typedef decltype(_Arg2PFNHelperThunk(stdx::declval<_T*>())) _Argument2Type; 908 typedef decltype(_Arg3PFNHelperThunk(stdx::declval<_T*>())) _Argument3Type; 909 }; 910 911 task<void> _To_task(); 912 913 template <typename _Function> auto _IsVoidConversionHelper(_Function _Func, int) -> typename decltype(_Func(_To_task()), std::true_type()); 914 template <typename _Function> std::false_type _IsVoidConversionHelper(_Function _Func, ...); 915 916 template <typename T> std::true_type _VoidIsTaskHelper(task<T> _Arg, int); 917 template <typename T> std::false_type _VoidIsTaskHelper(T _Arg, ...); 918 919 template<typename _Function, typename _ExpectedParameterType, const bool _IsVoidConversion = std::is_same<decltype(_IsVoidConversionHelper(stdx::declval<_Function>(), 0)), std::true_type>::value, const size_t _Count = _FunctorTypeTraits<_Function>::_ArgumentCount> 920 struct _FunctionTypeTraits 921 { 922 typedef typename _Unhat<typename _FunctorTypeTraits<_Function>::_Argument2Type>::_Value _FuncRetType; 923 static_assert(std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, _ExpectedParameterType>::value || 924 std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, task<_ExpectedParameterType>>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)"); 925 926 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task; 927 }; 928 929 //if there is a continuation parameter, then must use void/no return value 930 template<typename _Function, typename _ExpectedParameterType, const bool _IsVoidConversion> 931 struct _FunctionTypeTraits<_Function, _ExpectedParameterType, _IsVoidConversion, 1> 932 { 933 typedef void _FuncRetType; 934 static_assert(std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, _ExpectedParameterType>::value || 935 std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, task<_ExpectedParameterType>>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)"); 936 937 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task; 938 }; 939 940 template<typename _Function> 941 struct _FunctionTypeTraits<_Function, void, true, 1> 942 { 943 typedef void _FuncRetType; 944 static_assert(std::is_same<typename _FunctorTypeTraits<_Function>::_Argument1Type, decltype(_To_task())>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)"); 945 946 typedef decltype(_VoidIsTaskHelper(stdx::declval<_FunctorTypeTraits<_Function>::_Argument1Type>(), 0)) _Takes_task; 947 }; 948 949 template<typename _Function> 950 struct _FunctionTypeTraits<_Function, void, false, 1> 951 { 952 typedef typename _Unhat<typename _FunctorTypeTraits<_Function>::_Argument1Type>::_Value _FuncRetType; 953 954 typedef std::false_type _Takes_task; 955 }; 956 957 template<typename _Function, typename _ExpectedParameterType, const bool _IsVoidConversion> 958 struct _FunctionTypeTraits<_Function, _ExpectedParameterType, _IsVoidConversion, 0> 959 { 960 typedef void _FuncRetType; 961 962 typedef std::false_type _Takes_task; 963 }; 964 965 template<typename _Function, typename _ReturnType> 966 struct _ContinuationTypeTraits 967 { 968 typedef typename task<typename _TaskTypeTraits<typename _FunctionTypeTraits<_Function, _ReturnType>::_FuncRetType>::_TaskRetType_abi> _TaskOfType; 969 }; 970 971 // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is 972 // declared, the constructor may or may not perform unwrapping. For eg. 973 // 974 // This declaration SHOULD NOT cause unwrapping 975 // task<task<void>> t1([]() -> task<void> { 976 // task<void> t2([]() {}); 977 // return t2; 978 // }); 979 // 980 // This declaration SHOULD cause unwrapping 981 // task<void>> t1([]() -> task<void> { 982 // task<void> t2([]() {}); 983 // return t2; 984 // }); 985 // If the type of the task is the same as the return type of the function, no unwrapping should take place. Else normal rules apply. 986 template <typename _TaskType, typename _FuncRetType> 987 struct _InitFunctorTypeTraits 988 { 989 typedef typename _TaskTypeTraits<_FuncRetType>::_AsyncKind _AsyncKind; 990 static const bool _IsAsyncTask = _TaskTypeTraits<_FuncRetType>::_IsAsyncTask; 991 static const bool _IsUnwrappedTaskOrAsync = _TaskTypeTraits<_FuncRetType>::_IsUnwrappedTaskOrAsync; 992 }; 993 994 template<typename T> 995 struct _InitFunctorTypeTraits<T, T> 996 { 997 typedef _TypeSelectorNoAsync _AsyncKind; 998 static const bool _IsAsyncTask = false; 999 static const bool _IsUnwrappedTaskOrAsync = false; 1000 }; 1001 /// <summary> 1002 /// Helper object used for LWT invocation. 1003 /// </summary> 1004 struct _TaskProcThunk 1005 { 1006 _TaskProcThunk(const std::function<HRESULT(void)> & _Callback) : 1007 _M_func(_Callback) 1008 { 1009 } 1010 1011 static void __cdecl _Bridge(void *_PData) 1012 { 1013 _TaskProcThunk *_PThunk = reinterpret_cast<_TaskProcThunk *>(_PData); 1014 #if _MSC_VER >= 1800 1015 _Holder _ThunkHolder(_PThunk); 1016 #endif 1017 _PThunk->_M_func(); 1018 #if _MSC_VER < 1800 1019 delete _PThunk; 1020 #endif 1021 } 1022 private: 1023 #if _MSC_VER >= 1800 1024 // RAII holder 1025 struct _Holder 1026 { 1027 _Holder(_TaskProcThunk * _PThunk) : _M_pThunk(_PThunk) 1028 { 1029 } 1030 1031 ~_Holder() 1032 { 1033 delete _M_pThunk; 1034 } 1035 1036 _TaskProcThunk * _M_pThunk; 1037 1038 private: 1039 _Holder& operator=(const _Holder&); 1040 }; 1041 #endif 1042 std::function<HRESULT(void)> _M_func; 1043 _TaskProcThunk& operator=(const _TaskProcThunk&); 1044 }; 1045 1046 /// <summary> 1047 /// Schedule a functor with automatic inlining. Note that this is "fire and forget" scheduling, which cannot be 1048 /// waited on or canceled after scheduling. 1049 /// This schedule method will perform automatic inlining base on <paramref value="_InliningMode"/>. 1050 /// </summary> 1051 /// <param name="_Func"> 1052 /// The user functor need to be scheduled. 1053 /// </param> 1054 /// <param name="_InliningMode"> 1055 /// The inlining scheduling policy for current functor. 1056 /// </param> 1057 #if _MSC_VER >= 1800 1058 typedef Concurrency::details::_TaskInliningMode_t _TaskInliningMode; 1059 #else 1060 typedef Concurrency::details::_TaskInliningMode _TaskInliningMode; 1061 #endif 1062 static void _ScheduleFuncWithAutoInline(const std::function<HRESULT(void)> & _Func, _TaskInliningMode _InliningMode) 1063 { 1064 #if _MSC_VER >= 1800 1065 Concurrency::details::_TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge, new _TaskProcThunk(_Func), _InliningMode); 1066 #else 1067 Concurrency::details::_StackGuard _Guard; 1068 if (_Guard._ShouldInline(_InliningMode)) 1069 { 1070 _Func(); 1071 } 1072 else 1073 { 1074 Concurrency::details::_CurrentScheduler::_ScheduleTask(reinterpret_cast<Concurrency::TaskProc>(&_TaskProcThunk::_Bridge), new _TaskProcThunk(_Func)); 1075 } 1076 #endif 1077 } 1078 class _ContextCallback 1079 { 1080 typedef std::function<HRESULT(void)> _CallbackFunction; 1081 1082 public: 1083 1084 static _ContextCallback _CaptureCurrent() 1085 { 1086 _ContextCallback _Context; 1087 _Context._Capture(); 1088 return _Context; 1089 } 1090 1091 ~_ContextCallback() 1092 { 1093 _Reset(); 1094 } 1095 1096 _ContextCallback(bool _DeferCapture = false) 1097 { 1098 if (_DeferCapture) 1099 { 1100 _M_context._M_captureMethod = _S_captureDeferred; 1101 } 1102 else 1103 { 1104 _M_context._M_pContextCallback = nullptr; 1105 } 1106 } 1107 1108 // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context). 1109 void _Resolve(bool _CaptureCurrent) 1110 { 1111 if (_M_context._M_captureMethod == _S_captureDeferred) 1112 { 1113 _M_context._M_pContextCallback = nullptr; 1114 1115 if (_CaptureCurrent) 1116 { 1117 if (_IsCurrentOriginSTA()) 1118 { 1119 _Capture(); 1120 } 1121 #if _UITHREADCTXT_SUPPORT 1122 else 1123 { 1124 // This method will fail if not called from the UI thread. 1125 HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback); 1126 if (FAILED(_Hr)) 1127 { 1128 _M_context._M_pContextCallback = nullptr; 1129 } 1130 } 1131 #endif // _UITHREADCTXT_SUPPORT 1132 } 1133 } 1134 } 1135 1136 void _Capture() 1137 { 1138 HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback)); 1139 if (FAILED(_Hr)) 1140 { 1141 _M_context._M_pContextCallback = nullptr; 1142 } 1143 } 1144 1145 _ContextCallback(const _ContextCallback& _Src) 1146 { 1147 _Assign(_Src._M_context._M_pContextCallback); 1148 } 1149 1150 _ContextCallback(_ContextCallback&& _Src) 1151 { 1152 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback; 1153 _Src._M_context._M_pContextCallback = nullptr; 1154 } 1155 1156 _ContextCallback& operator=(const _ContextCallback& _Src) 1157 { 1158 if (this != &_Src) 1159 { 1160 _Reset(); 1161 _Assign(_Src._M_context._M_pContextCallback); 1162 } 1163 return *this; 1164 } 1165 1166 _ContextCallback& operator=(_ContextCallback&& _Src) 1167 { 1168 if (this != &_Src) 1169 { 1170 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback; 1171 _Src._M_context._M_pContextCallback = nullptr; 1172 } 1173 return *this; 1174 } 1175 1176 bool _HasCapturedContext() const 1177 { 1178 _CONCRT_ASSERT(_M_context._M_captureMethod != _S_captureDeferred); 1179 return (_M_context._M_pContextCallback != nullptr); 1180 } 1181 1182 HRESULT _CallInContext(_CallbackFunction _Func) const 1183 { 1184 if (!_HasCapturedContext()) 1185 { 1186 _Func(); 1187 } 1188 else 1189 { 1190 ComCallData callData; 1191 ZeroMemory(&callData, sizeof(callData)); 1192 callData.pUserDefined = reinterpret_cast<void *>(&_Func); 1193 1194 HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr); 1195 if (FAILED(_Hr)) 1196 { 1197 return _Hr; 1198 } 1199 } 1200 return S_OK; 1201 } 1202 1203 bool operator==(const _ContextCallback& _Rhs) const 1204 { 1205 return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback); 1206 } 1207 1208 bool operator!=(const _ContextCallback& _Rhs) const 1209 { 1210 return !(operator==(_Rhs)); 1211 } 1212 1213 private: 1214 1215 void _Reset() 1216 { 1217 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) 1218 { 1219 _M_context._M_pContextCallback->Release(); 1220 } 1221 } 1222 1223 void _Assign(IContextCallback *_PContextCallback) 1224 { 1225 _M_context._M_pContextCallback = _PContextCallback; 1226 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr) 1227 { 1228 _M_context._M_pContextCallback->AddRef(); 1229 } 1230 } 1231 1232 static HRESULT __stdcall _Bridge(ComCallData *_PParam) 1233 { 1234 _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined); 1235 return (*pFunc)(); 1236 } 1237 1238 // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know) 1239 static bool _IsCurrentOriginSTA() 1240 { 1241 APTTYPE _AptType; 1242 APTTYPEQUALIFIER _AptTypeQualifier; 1243 1244 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); 1245 if (SUCCEEDED(hr)) 1246 { 1247 // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether 1248 // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in 1249 // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA, 1250 // since variables used within a neutral apartment are expected to be apartment neutral. 1251 switch (_AptType) 1252 { 1253 case APTTYPE_MAINSTA: 1254 case APTTYPE_STA: 1255 return true; 1256 default: 1257 break; 1258 } 1259 } 1260 return false; 1261 } 1262 1263 union 1264 { 1265 IContextCallback *_M_pContextCallback; 1266 size_t _M_captureMethod; 1267 } _M_context; 1268 1269 static const size_t _S_captureDeferred = 1; 1270 }; 1271 1272 #if _MSC_VER >= 1800 1273 template<typename _Type> 1274 struct _ResultHolder 1275 { 1276 void Set(const _Type& _type) 1277 { 1278 _Result = _type; 1279 } 1280 1281 _Type Get() 1282 { 1283 return _Result; 1284 } 1285 1286 _Type _Result; 1287 }; 1288 1289 template<typename _Type> 1290 struct _ResultHolder<_Type*> 1291 { 1292 void Set(_Type* const & _type) 1293 { 1294 _M_Result = _type; 1295 } 1296 1297 _Type* Get() 1298 { 1299 return _M_Result.Get(); 1300 } 1301 private: 1302 // ::Platform::Agile handle specialization of all hats 1303 // including ::Platform::String and ::Platform::Array 1304 Agile<_Type*> _M_Result; 1305 }; 1306 1307 // 1308 // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs. 1309 // 1310 template<typename _Type> 1311 struct _ResultHolder<std::vector<_Type*>> 1312 { 1313 void Set(const std::vector<_Type*>& _type) 1314 { 1315 _Result.reserve(_type.size()); 1316 1317 for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask) 1318 { 1319 _Result.emplace_back(*_PTask); 1320 } 1321 } 1322 1323 std::vector<_Type*> Get() 1324 { 1325 // Return vectory<T^> with the objects that are marshaled in the proper appartment 1326 std::vector<_Type*> _Return; 1327 _Return.reserve(_Result.size()); 1328 1329 for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask) 1330 { 1331 _Return.push_back(_PTask->Get()); // Agile will marshal the object to appropriate appartment if neccessary 1332 } 1333 1334 return _Return; 1335 } 1336 1337 std::vector< Agile<_Type*> > _Result; 1338 }; 1339 1340 template<typename _Type> 1341 struct _ResultHolder<std::pair<_Type*, void*> > 1342 { 1343 void Set(const std::pair<_Type*, size_t>& _type) 1344 { 1345 _M_Result = _type; 1346 } 1347 1348 std::pair<_Type*, size_t> Get() 1349 { 1350 return std::make_pair(_M_Result.first, _M_Result.second); 1351 } 1352 private: 1353 std::pair<Agile<_Type*>, size_t> _M_Result; 1354 }; 1355 #else 1356 template<typename _Type> 1357 struct _ResultContext 1358 { 1359 static _ContextCallback _GetContext(bool /* _RuntimeAggregate */) 1360 { 1361 return _ContextCallback(); 1362 } 1363 1364 static _Type _GetValue(_Type _ObjInCtx, const _ContextCallback & /* _Ctx */, bool /* _RuntimeAggregate */) 1365 { 1366 return _ObjInCtx; 1367 } 1368 }; 1369 1370 template<typename _Type, size_t N = 0, bool bIsArray = std::is_array<_Type>::value> 1371 struct _MarshalHelper 1372 { 1373 }; 1374 template<typename _Type, size_t N> 1375 struct _MarshalHelper<_Type, N, true> 1376 { 1377 static _Type* _Perform(_Type(&_ObjInCtx)[N], const _ContextCallback& _Ctx) 1378 { 1379 static_assert(__is_valid_winrt_type(_Type*), "must be a WinRT array compatible type"); 1380 if (_ObjInCtx == nullptr) 1381 { 1382 return nullptr; 1383 } 1384 1385 HRESULT _Hr; 1386 IStream * _PStream; 1387 _Ctx._CallInContext([&]() -> HRESULT { 1388 // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr. 1389 // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled. 1390 1391 IUnknown * _PUnk = winrt_array_type::create(_ObjInCtx, N); 1392 _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream); 1393 return S_OK; 1394 }); 1395 1396 // With an APPX manifest, this call should never fail. 1397 _CONCRT_ASSERT(SUCCEEDED(_Hr)); 1398 1399 _Type* _Proxy; 1400 // 1401 // Cannot use IID_PPV_ARGS with ^ types. 1402 // 1403 _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy)); 1404 if (FAILED(_Hr)) 1405 { 1406 throw std::make_exception_ptr(_Hr); 1407 } 1408 return _Proxy; 1409 } 1410 }; 1411 template<typename _Type> 1412 struct _MarshalHelper<_Type, 0, false> 1413 { 1414 static _Type* _Perform(_Type* _ObjInCtx, const _ContextCallback& _Ctx) 1415 { 1416 static_assert(std::is_base_of<IUnknown, _Type>::value || __is_valid_winrt_type(_Type), "must be a COM or WinRT type"); 1417 if (_ObjInCtx == nullptr) 1418 { 1419 return nullptr; 1420 } 1421 1422 HRESULT _Hr; 1423 IStream * _PStream; 1424 _Ctx._CallInContext([&]() -> HRESULT { 1425 // It isn't safe to simply reinterpret_cast a hat type to IUnknown* because some types do not have a real vtable ptr. 1426 // Instead, we could to create a property value to make it "grow" the vtable ptr but instead primitives are not marshalled. 1427 1428 IUnknown * _PUnk = winrt_type<_Type>::create(_ObjInCtx); 1429 _Hr = CoMarshalInterThreadInterfaceInStream(winrt_type<_Type>::getuuid(), _PUnk, &_PStream); 1430 return S_OK; 1431 }); 1432 1433 // With an APPX manifest, this call should never fail. 1434 _CONCRT_ASSERT(SUCCEEDED(_Hr)); 1435 1436 _Type* _Proxy; 1437 // 1438 // Cannot use IID_PPV_ARGS with ^ types. 1439 // 1440 _Hr = CoGetInterfaceAndReleaseStream(_PStream, winrt_type<_Type>::getuuid(), reinterpret_cast<void**>(&_Proxy)); 1441 if (FAILED(_Hr)) 1442 { 1443 throw std::make_exception_ptr(_Hr); 1444 } 1445 return _Proxy; 1446 } 1447 }; 1448 1449 // Arrays must be converted to IPropertyValue objects. 1450 1451 template<> 1452 struct _MarshalHelper<HSTRING__> 1453 { 1454 static HSTRING _Perform(HSTRING _ObjInCtx, const _ContextCallback& _Ctx) 1455 { 1456 return _ObjInCtx; 1457 } 1458 }; 1459 1460 template<typename _Type> 1461 _Type* _Marshal(_Type* _ObjInCtx, const _ContextCallback& _Ctx) 1462 { 1463 return _MarshalHelper<_Type>::_Perform(_ObjInCtx, _Ctx); 1464 } 1465 1466 template<typename _Type> 1467 struct _InContext 1468 { 1469 static _Type _Get(_Type _ObjInCtx, const _ContextCallback& _Ctx) 1470 { 1471 return _ObjInCtx; 1472 } 1473 }; 1474 1475 template<typename _Type> 1476 struct _InContext<_Type*> 1477 { 1478 static _Type* _Get(_Type* _ObjInCtx, const _ContextCallback& _Ctx) 1479 { 1480 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent(); 1481 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext) 1482 { 1483 return _ObjInCtx; 1484 } 1485 1486 // 1487 // The object is from another apartment. If it's marshalable, do so. 1488 // 1489 return _Marshal<_Type>(_ObjInCtx, _Ctx); 1490 } 1491 }; 1492 1493 template<typename _Type> 1494 struct _ResultContext<_Type*> 1495 { 1496 static _Type* _GetValue(_Type* _ObjInCtx, const _ContextCallback& _Ctx, bool /* _RuntimeAggregate */) 1497 { 1498 return _InContext<_Type*>::_Get(_ObjInCtx, _Ctx); 1499 } 1500 1501 static _ContextCallback _GetContext(bool /* _RuntimeAggregate */) 1502 { 1503 return _ContextCallback::_CaptureCurrent(); 1504 } 1505 }; 1506 1507 // 1508 // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs. 1509 // 1510 template<typename _Type> 1511 struct _ResultContext<std::vector<_Type*>> 1512 { 1513 static std::vector<_Type*> _GetValue(std::vector<_Type*> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate) 1514 { 1515 if (!_RuntimeAggregate) 1516 { 1517 return _ObjInCtx; 1518 } 1519 1520 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent(); 1521 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext) 1522 { 1523 return _ObjInCtx; 1524 } 1525 1526 for (auto _It = _ObjInCtx.begin(); _It != _ObjInCtx.end(); ++_It) 1527 { 1528 *_It = _Marshal<_Type>(*_It, _Ctx); 1529 } 1530 1531 return _ObjInCtx; 1532 } 1533 1534 static _ContextCallback _GetContext(bool _RuntimeAggregate) 1535 { 1536 if (!_RuntimeAggregate) 1537 { 1538 return _ContextCallback(); 1539 } 1540 else 1541 { 1542 return _ContextCallback::_CaptureCurrent(); 1543 } 1544 } 1545 }; 1546 1547 template<typename _Type> 1548 struct _ResultContext<std::pair<_Type*, size_t>> 1549 { 1550 static std::pair<_Type*, size_t> _GetValue(std::pair<_Type*, size_t> _ObjInCtx, const _ContextCallback& _Ctx, bool _RuntimeAggregate) 1551 { 1552 if (!_RuntimeAggregate) 1553 { 1554 return _ObjInCtx; 1555 } 1556 1557 _ContextCallback _CurrentContext = _ContextCallback::_CaptureCurrent(); 1558 if (!_Ctx._HasCapturedContext() || _Ctx == _CurrentContext) 1559 { 1560 return _ObjInCtx; 1561 } 1562 1563 return std::pair<_Type*, size_t>(_Marshal<_Type>(_ObjInCtx.first, _Ctx), _ObjInCtx.second); 1564 } 1565 1566 static _ContextCallback _GetContext(bool _RuntimeAggregate) 1567 { 1568 if (!_RuntimeAggregate) 1569 { 1570 return _ContextCallback(); 1571 } 1572 else 1573 { 1574 return _ContextCallback::_CaptureCurrent(); 1575 } 1576 } 1577 }; 1578 #endif 1579 // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task. 1580 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception 1581 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast. 1582 struct _ExceptionHolder 1583 { 1584 #if _MSC_VER >= 1800 1585 private: 1586 void ReportUnhandledError() 1587 { 1588 if (_M_winRTException != nullptr) 1589 { 1590 throw _M_winRTException.Get(); 1591 } 1592 } 1593 public: 1594 explicit _ExceptionHolder(const std::exception_ptr& _E, const _TaskCreationCallstack &_stackTrace) : 1595 _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace) 1596 { 1597 } 1598 1599 explicit _ExceptionHolder(IRestrictedErrorInfo*& _E, const _TaskCreationCallstack &_stackTrace) : 1600 _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace) 1601 { 1602 } 1603 #else 1604 explicit _ExceptionHolder(const std::exception_ptr& _E, void* _SourceAddressHint) : 1605 _M_exceptionObserved(0), _M_stdException(_E), _M_disassembleMe(_SourceAddressHint) 1606 { 1607 } 1608 1609 explicit _ExceptionHolder(IRestrictedErrorInfo*& _E, void* _SourceAddressHint) : 1610 _M_exceptionObserved(0), _M_disassembleMe(_SourceAddressHint), _M_winRTException(_E) 1611 { 1612 } 1613 #endif 1614 __declspec(noinline) 1615 ~_ExceptionHolder() 1616 { 1617 if (_M_exceptionObserved == 0) 1618 { 1619 #if _MSC_VER >= 1800 1620 // If you are trapped here, it means an exception thrown in task chain didn't get handled. 1621 // Please add task-based continuation to handle all exceptions coming from tasks. 1622 // this->_M_stackTrace keeps the creation callstack of the task generates this exception. 1623 _REPORT_PPLTASK_UNOBSERVED_EXCEPTION(); 1624 #else 1625 // Disassemble at this->_M_disassembleMe to get to the source location right after either the creation of the task (constructor 1626 // or then method) that encountered this exception, or the set_exception call for a task_completion_event. 1627 Concurrency::details::_ReportUnobservedException(); 1628 #endif 1629 } 1630 } 1631 1632 void _RethrowUserException() 1633 { 1634 if (_M_exceptionObserved == 0) 1635 { 1636 #if _MSC_VER >= 1800 1637 Concurrency::details::atomic_exchange(_M_exceptionObserved, 1l); 1638 #else 1639 _InterlockedExchange(&_M_exceptionObserved, 1); 1640 #endif 1641 } 1642 1643 if (_M_winRTException != nullptr) 1644 { 1645 throw _M_winRTException.Get(); 1646 } 1647 std::rethrow_exception(_M_stdException); 1648 } 1649 1650 // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that 1651 // are unobserved when the exception holder is destructed will terminate the process. 1652 #if _MSC_VER >= 1800 1653 Concurrency::details::atomic_long _M_exceptionObserved; 1654 #else 1655 long volatile _M_exceptionObserved; 1656 #endif 1657 1658 // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered. 1659 std::exception_ptr _M_stdException; 1660 Microsoft::WRL::ComPtr<IRestrictedErrorInfo> _M_winRTException; 1661 1662 // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task, 1663 // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call 1664 // is to task_completion_event::set_exception, the set_exception method was the source of the exception. 1665 // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging. 1666 #if _MSC_VER >= 1800 1667 _TaskCreationCallstack _M_stackTrace; 1668 #else 1669 void* _M_disassembleMe; 1670 #endif 1671 }; 1672 1673 #ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED 1674 #define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoImpl_DEFINED 1675 extern const __declspec(selectany) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl[] = L"Concurrency_winrt.details._AsyncInfoImpl"; 1676 #endif 1677 1678 /// <summary> 1679 /// Base converter class for converting asynchronous interfaces to IAsyncOperation 1680 /// </summary> 1681 template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result_abi> 1682 struct _AsyncInfoImpl abstract : public Microsoft::WRL::RuntimeClass< 1683 Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>, 1684 Microsoft::WRL::Implements<Microsoft::WRL::AsyncBase<_CompletionHandlerType>>> 1685 { 1686 InspectableClass(RuntimeClass_Concurrency_winrt_details__AsyncInfoImpl, BaseTrust) 1687 public: 1688 // The async action, action with progress or operation with progress that this stub forwards to. 1689 #if _MSC_VER >= 1800 1690 Agile<_AsyncOperationType> _M_asyncInfo; 1691 #else 1692 Microsoft::WRL::ComPtr<_AsyncOperationType> _M_asyncInfo; 1693 // The context in which this async info is valid - may be different from the context where the completion handler runs, 1694 // and may require marshalling before it is used. 1695 _ContextCallback _M_asyncInfoContext; 1696 #endif 1697 1698 Microsoft::WRL::ComPtr<_CompletionHandlerType> _M_CompletedHandler; 1699 1700 _AsyncInfoImpl(_AsyncOperationType* _AsyncInfo) : _M_asyncInfo(_AsyncInfo) 1701 #if _MSC_VER < 1800 1702 , _M_asyncInfoContext(_ContextCallback::_CaptureCurrent()) 1703 #endif 1704 {} 1705 1706 public: 1707 virtual HRESULT OnStart() { return S_OK; } 1708 virtual void OnCancel() { 1709 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 1710 HRESULT hr; 1711 #if _MSC_VER >= 1800 1712 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf()))) 1713 #else 1714 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo))) 1715 #endif 1716 pAsyncInfo->Cancel(); 1717 else 1718 throw std::make_exception_ptr(hr); 1719 } 1720 virtual void OnClose() { 1721 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 1722 HRESULT hr; 1723 #if _MSC_VER >= 1800 1724 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf()))) 1725 #else 1726 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo))) 1727 #endif 1728 pAsyncInfo->Close(); 1729 else 1730 throw std::make_exception_ptr(hr); 1731 } 1732 1733 virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode) 1734 { 1735 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 1736 HRESULT hr; 1737 #if _MSC_VER >= 1800 1738 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf()))) 1739 #else 1740 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo))) 1741 #endif 1742 return pAsyncInfo->get_ErrorCode(errorCode); 1743 return hr; 1744 } 1745 1746 virtual STDMETHODIMP get_Id(UINT* id) 1747 { 1748 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 1749 HRESULT hr; 1750 #if _MSC_VER >= 1800 1751 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf()))) 1752 #else 1753 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo))) 1754 #endif 1755 return pAsyncInfo->get_Id(id); 1756 return hr; 1757 } 1758 1759 virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus *status) 1760 { 1761 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 1762 HRESULT hr; 1763 #if _MSC_VER >= 1800 1764 if (SUCCEEDED(hr = _M_asyncInfo.Get()->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf()))) 1765 #else 1766 if (SUCCEEDED(hr = _M_asyncInfo.As(&pAsyncInfo))) 1767 #endif 1768 return pAsyncInfo->get_Status(status); 1769 return hr; 1770 } 1771 1772 virtual STDMETHODIMP GetResults(_Result_abi*) { throw std::runtime_error("derived class must implement"); } 1773 1774 virtual STDMETHODIMP get_Completed(_CompletionHandlerType** handler) 1775 { 1776 if (!handler) return E_POINTER; 1777 _M_CompletedHandler.CopyTo(handler); 1778 return S_OK; 1779 } 1780 1781 virtual STDMETHODIMP put_Completed(_CompletionHandlerType* value) 1782 { 1783 _M_CompletedHandler = value; 1784 Microsoft::WRL::ComPtr<_CompletionHandlerType> handler = Microsoft::WRL::Callback<_CompletionHandlerType>([&](_AsyncOperationType*, ABI::Windows::Foundation::AsyncStatus status) -> HRESULT { 1785 #if _MSC_VER < 1800 1786 // Update the saved _M_asyncInfo with a proxy valid in the current context if required. Some Windows APIs return an IAsyncInfo 1787 // that is only valid for the thread that called the API to retrieve. Since this completion handler can run on any thread, we 1788 // need to ensure that the async info is valid in the current apartment. _M_asyncInfo will be accessed via calls to 'this' inside 1789 // _AsyncInit. 1790 _M_asyncInfo = _ResultContext<_AsyncOperationType*>::_GetValue(_M_asyncInfo.Get(), _M_asyncInfoContext, false); 1791 #endif 1792 return _M_CompletedHandler->Invoke(_M_asyncInfo.Get(), status); 1793 }); 1794 #if _MSC_VER >= 1800 1795 return _M_asyncInfo.Get()->put_Completed(handler.Get()); 1796 #else 1797 return _M_asyncInfo->put_Completed(handler.Get()); 1798 #endif 1799 } 1800 }; 1801 1802 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncOperationToAsyncOperationConverter[] = L"_IAsyncOperationToAsyncOperationConverter"; 1803 1804 /// <summary> 1805 /// Class _IAsyncOperationToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T> 1806 /// </summary> 1807 template<typename _Result> 1808 struct _IAsyncOperationToAsyncOperationConverter : 1809 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperation<_Result>, 1810 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>, 1811 typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Result>*>()))>::type> 1812 { 1813 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_Result>*>()))>::type _Result_abi; 1814 1815 InspectableClass(RuntimeClass_IAsyncOperationToAsyncOperationConverter, BaseTrust) 1816 public: 1817 _IAsyncOperationToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncOperation<_Result>* _Operation) : 1818 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperation<_Result>, 1819 ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_Result>, 1820 _Result_abi>(_Operation) {} 1821 public: 1822 virtual STDMETHODIMP GetResults(_Result_abi* results) override { 1823 if (!results) return E_POINTER; 1824 #if _MSC_VER >= 1800 1825 return _M_asyncInfo.Get()->GetResults(results); 1826 #else 1827 return _M_asyncInfo->GetResults(results); 1828 #endif 1829 } 1830 }; 1831 1832 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter[] = L"_IAsyncOperationWithProgressToAsyncOperationConverter"; 1833 1834 /// <summary> 1835 /// Class _IAsyncOperationWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncOperationWithProgress<T> into IAsyncOperation<T> 1836 /// </summary> 1837 template<typename _Result, typename _Progress> 1838 struct _IAsyncOperationWithProgressToAsyncOperationConverter : 1839 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>, 1840 ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>, 1841 typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>*>()))>::type> 1842 { 1843 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>*>()))>::type _Result_abi; 1844 1845 InspectableClass(RuntimeClass_IAsyncOperationWithProgressToAsyncOperationConverter, BaseTrust) 1846 public: 1847 _IAsyncOperationWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _Operation) : 1848 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>, 1849 ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_Result, _Progress>, 1850 _Result_abi>(_Operation) {} 1851 public: 1852 virtual STDMETHODIMP GetResults(_Result_abi* results) override { 1853 if (!results) return E_POINTER; 1854 #if _MSC_VER >= 1800 1855 return _M_asyncInfo.Get()->GetResults(results); 1856 #else 1857 return _M_asyncInfo->GetResults(results); 1858 #endif 1859 } 1860 }; 1861 1862 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionToAsyncOperationConverter[] = L"_IAsyncActionToAsyncOperationConverter"; 1863 1864 /// <summary> 1865 /// Class _IAsyncActionToAsyncOperationConverter is used to convert an instance of IAsyncAction into IAsyncOperation<_Unit_type> 1866 /// </summary> 1867 struct _IAsyncActionToAsyncOperationConverter : 1868 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction, 1869 ABI::Windows::Foundation::IAsyncActionCompletedHandler, 1870 _Unit_type> 1871 { 1872 InspectableClass(RuntimeClass_IAsyncActionToAsyncOperationConverter, BaseTrust) 1873 public: 1874 _IAsyncActionToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncAction* _Operation) : 1875 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncAction, 1876 ABI::Windows::Foundation::IAsyncActionCompletedHandler, 1877 _Unit_type>(_Operation) {} 1878 1879 public: 1880 virtual STDMETHODIMP GetResults(details::_Unit_type* results) 1881 { 1882 if (!results) return E_POINTER; 1883 // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value. 1884 #if _MSC_VER >= 1800 1885 HRESULT hr = _M_asyncInfo.Get()->GetResults(); 1886 #else 1887 HRESULT hr = _M_asyncInfo->GetResults(); 1888 #endif 1889 if (SUCCEEDED(hr)) *results = _Unit_type(); 1890 return hr; 1891 } 1892 }; 1893 1894 extern const __declspec(selectany) WCHAR RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter[] = L"_IAsyncActionWithProgressToAsyncOperationConverter"; 1895 1896 /// <summary> 1897 /// Class _IAsyncActionWithProgressToAsyncOperationConverter is used to convert an instance of IAsyncActionWithProgress into IAsyncOperation<_Unit_type> 1898 /// </summary> 1899 template<typename _Progress> 1900 struct _IAsyncActionWithProgressToAsyncOperationConverter : 1901 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>, 1902 ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>, 1903 _Unit_type> 1904 { 1905 InspectableClass(RuntimeClass_IAsyncActionWithProgressToAsyncOperationConverter, BaseTrust) 1906 public: 1907 _IAsyncActionWithProgressToAsyncOperationConverter(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* _Action) : 1908 _AsyncInfoImpl<ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>, 1909 ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_Progress>, 1910 _Unit_type>(_Action) {} 1911 public: 1912 virtual STDMETHODIMP GetResults(_Unit_type* results) override 1913 { 1914 if (!results) return E_POINTER; 1915 // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value. 1916 #if _MSC_VER >= 1800 1917 HRESULT hr = _M_asyncInfo.Get()->GetResults(); 1918 #else 1919 HRESULT hr = _M_asyncInfo->GetResults(); 1920 #endif 1921 if (SUCCEEDED(hr)) *results = _Unit_type(); 1922 return hr; 1923 } 1924 }; 1925 } 1926 1927 /// <summary> 1928 /// The <c>task_continuation_context</c> class allows you to specify where you would like a continuation to be executed. 1929 /// It is only useful to use this class from a Windows Store app. For non-Windows Store apps, the task continuation's 1930 /// execution context is determined by the runtime, and not configurable. 1931 /// </summary> 1932 /// <seealso cref="task Class"/> 1933 /**/ 1934 class task_continuation_context : public details::_ContextCallback 1935 { 1936 public: 1937 1938 /// <summary> 1939 /// Creates the default task continuation context. 1940 /// </summary> 1941 /// <returns> 1942 /// The default continuation context. 1943 /// </returns> 1944 /// <remarks> 1945 /// The default context is used if you don't specifiy a continuation context when you call the <c>then</c> method. In Windows 1946 /// applications for Windows 7 and below, as well as desktop applications on Windows 8 and higher, the runtime determines where 1947 /// task continuations will execute. However, in a Windows Store app, the default continuation context for a continuation on an 1948 /// apartment aware task is the apartment where <c>then</c> is invoked. 1949 /// <para>An apartment aware task is a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such 1950 /// a task. Therefore, if you schedule a continuation on an apartment aware task in a Windows Runtime STA, the continuation will execute in 1951 /// that STA.</para> 1952 /// <para>A continuation on a non-apartment aware task will execute in a context the Runtime chooses.</para> 1953 /// </remarks> 1954 /**/ 1955 static task_continuation_context use_default() 1956 { 1957 // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then() 1958 return task_continuation_context(true); // sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle 1959 } 1960 1961 /// <summary> 1962 /// Creates a task continuation context which allows the Runtime to choose the execution context for a continuation. 1963 /// </summary> 1964 /// <returns> 1965 /// A task continuation context that represents an arbitrary location. 1966 /// </returns> 1967 /// <remarks> 1968 /// When this continuation context is used the continuation will execute in a context the runtime chooses even if the antecedent task 1969 /// is apartment aware. 1970 /// <para><c>use_arbitrary</c> can be used to turn off the default behavior for a continuation on an apartment 1971 /// aware task created in an STA. </para> 1972 /// <para>This method is only available to Windows Store apps.</para> 1973 /// </remarks> 1974 /**/ 1975 static task_continuation_context use_arbitrary() 1976 { 1977 task_continuation_context _Arbitrary(true); 1978 _Arbitrary._Resolve(false); 1979 return _Arbitrary; 1980 } 1981 1982 /// <summary> 1983 /// Returns a task continuation context object that represents the current execution context. 1984 /// </summary> 1985 /// <returns> 1986 /// The current execution context. 1987 /// </returns> 1988 /// <remarks> 1989 /// This method captures the caller's Windows Runtime context so that continuations can be executed in the right apartment. 1990 /// <para>The value returned by <c>use_current</c> can be used to indicate to the Runtime that the continuation should execute in 1991 /// the captured context (STA vs MTA) regardless of whether or not the antecedent task is apartment aware. An apartment aware task is 1992 /// a task that unwraps a Windows Runtime <c>IAsyncInfo</c> interface, or a task that is descended from such a task. </para> 1993 /// <para>This method is only available to Windows Store apps.</para> 1994 /// </remarks> 1995 /**/ 1996 static task_continuation_context use_current() 1997 { 1998 task_continuation_context _Current(true); 1999 _Current._Resolve(true); 2000 return _Current; 2001 } 2002 2003 private: 2004 2005 task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture) 2006 { 2007 } 2008 }; 2009 2010 #if _MSC_VER >= 1800 2011 class task_options; 2012 namespace details 2013 { 2014 struct _Internal_task_options 2015 { 2016 bool _M_hasPresetCreationCallstack; 2017 _TaskCreationCallstack _M_presetCreationCallstack; 2018 2019 void _set_creation_callstack(const _TaskCreationCallstack &_callstack) 2020 { 2021 _M_hasPresetCreationCallstack = true; 2022 _M_presetCreationCallstack = _callstack; 2023 } 2024 _Internal_task_options() 2025 { 2026 _M_hasPresetCreationCallstack = false; 2027 } 2028 }; 2029 2030 inline _Internal_task_options &_get_internal_task_options(task_options &options); 2031 inline const _Internal_task_options &_get_internal_task_options(const task_options &options); 2032 } 2033 /// <summary> 2034 /// Represents the allowed options for creating a task 2035 /// </summary> 2036 class task_options 2037 { 2038 public: 2039 2040 2041 /// <summary> 2042 /// Default list of task creation options 2043 /// </summary> 2044 task_options() 2045 : _M_Scheduler(Concurrency::get_ambient_scheduler()), 2046 _M_CancellationToken(Concurrency::cancellation_token::none()), 2047 _M_ContinuationContext(task_continuation_context::use_default()), 2048 _M_HasCancellationToken(false), 2049 _M_HasScheduler(false) 2050 { 2051 } 2052 2053 /// <summary> 2054 /// Task option that specify a cancellation token 2055 /// </summary> 2056 task_options(Concurrency::cancellation_token _Token) 2057 : _M_Scheduler(Concurrency::get_ambient_scheduler()), 2058 _M_CancellationToken(_Token), 2059 _M_ContinuationContext(task_continuation_context::use_default()), 2060 _M_HasCancellationToken(true), 2061 _M_HasScheduler(false) 2062 { 2063 } 2064 2065 /// <summary> 2066 /// Task option that specify a continuation context. This is valid only for continuations (then) 2067 /// </summary> 2068 task_options(task_continuation_context _ContinuationContext) 2069 : _M_Scheduler(Concurrency::get_ambient_scheduler()), 2070 _M_CancellationToken(Concurrency::cancellation_token::none()), 2071 _M_ContinuationContext(_ContinuationContext), 2072 _M_HasCancellationToken(false), 2073 _M_HasScheduler(false) 2074 { 2075 } 2076 2077 /// <summary> 2078 /// Task option that specify a cancellation token and a continuation context. This is valid only for continuations (then) 2079 /// </summary> 2080 task_options(Concurrency::cancellation_token _Token, task_continuation_context _ContinuationContext) 2081 : _M_Scheduler(Concurrency::get_ambient_scheduler()), 2082 _M_CancellationToken(_Token), 2083 _M_ContinuationContext(_ContinuationContext), 2084 _M_HasCancellationToken(false), 2085 _M_HasScheduler(false) 2086 { 2087 } 2088 2089 /// <summary> 2090 /// Task option that specify a scheduler with shared lifetime 2091 /// </summary> 2092 template<typename _SchedType> 2093 task_options(std::shared_ptr<_SchedType> _Scheduler) 2094 : _M_Scheduler(std::move(_Scheduler)), 2095 _M_CancellationToken(cancellation_token::none()), 2096 _M_ContinuationContext(task_continuation_context::use_default()), 2097 _M_HasCancellationToken(false), 2098 _M_HasScheduler(true) 2099 { 2100 } 2101 2102 /// <summary> 2103 /// Task option that specify a scheduler reference 2104 /// </summary> 2105 task_options(Concurrency::scheduler_interface& _Scheduler) 2106 : _M_Scheduler(&_Scheduler), 2107 _M_CancellationToken(Concurrency::cancellation_token::none()), 2108 _M_ContinuationContext(task_continuation_context::use_default()), 2109 _M_HasCancellationToken(false), 2110 _M_HasScheduler(true) 2111 { 2112 } 2113 2114 /// <summary> 2115 /// Task option that specify a scheduler 2116 /// </summary> 2117 task_options(Concurrency::scheduler_ptr _Scheduler) 2118 : _M_Scheduler(std::move(_Scheduler)), 2119 _M_CancellationToken(Concurrency::cancellation_token::none()), 2120 _M_ContinuationContext(task_continuation_context::use_default()), 2121 _M_HasCancellationToken(false), 2122 _M_HasScheduler(true) 2123 { 2124 } 2125 2126 /// <summary> 2127 /// Task option copy constructor 2128 /// </summary> 2129 task_options(const task_options& _TaskOptions) 2130 : _M_Scheduler(_TaskOptions.get_scheduler()), 2131 _M_CancellationToken(_TaskOptions.get_cancellation_token()), 2132 _M_ContinuationContext(_TaskOptions.get_continuation_context()), 2133 _M_HasCancellationToken(_TaskOptions.has_cancellation_token()), 2134 _M_HasScheduler(_TaskOptions.has_scheduler()) 2135 { 2136 } 2137 2138 /// <summary> 2139 /// Sets the given token in the options 2140 /// </summary> 2141 void set_cancellation_token(Concurrency::cancellation_token _Token) 2142 { 2143 _M_CancellationToken = _Token; 2144 _M_HasCancellationToken = true; 2145 } 2146 2147 /// <summary> 2148 /// Sets the given continuation context in the options 2149 /// </summary> 2150 void set_continuation_context(task_continuation_context _ContinuationContext) 2151 { 2152 _M_ContinuationContext = _ContinuationContext; 2153 } 2154 2155 /// <summary> 2156 /// Indicates whether a cancellation token was specified by the user 2157 /// </summary> 2158 bool has_cancellation_token() const 2159 { 2160 return _M_HasCancellationToken; 2161 } 2162 2163 /// <summary> 2164 /// Returns the cancellation token 2165 /// </summary> 2166 Concurrency::cancellation_token get_cancellation_token() const 2167 { 2168 return _M_CancellationToken; 2169 } 2170 2171 /// <summary> 2172 /// Returns the continuation context 2173 /// </summary> 2174 task_continuation_context get_continuation_context() const 2175 { 2176 return _M_ContinuationContext; 2177 } 2178 2179 /// <summary> 2180 /// Indicates whether a scheduler n was specified by the user 2181 /// </summary> 2182 bool has_scheduler() const 2183 { 2184 return _M_HasScheduler; 2185 } 2186 2187 /// <summary> 2188 /// Returns the scheduler 2189 /// </summary> 2190 Concurrency::scheduler_ptr get_scheduler() const 2191 { 2192 return _M_Scheduler; 2193 } 2194 2195 private: 2196 2197 task_options const& operator=(task_options const& _Right); 2198 friend details::_Internal_task_options &details::_get_internal_task_options(task_options &); 2199 friend const details::_Internal_task_options &details::_get_internal_task_options(const task_options &); 2200 2201 Concurrency::scheduler_ptr _M_Scheduler; 2202 Concurrency::cancellation_token _M_CancellationToken; 2203 task_continuation_context _M_ContinuationContext; 2204 details::_Internal_task_options _M_InternalTaskOptions; 2205 bool _M_HasCancellationToken; 2206 bool _M_HasScheduler; 2207 }; 2208 #endif 2209 2210 namespace details 2211 { 2212 #if _MSC_VER >= 1800 2213 inline _Internal_task_options & _get_internal_task_options(task_options &options) 2214 { 2215 return options._M_InternalTaskOptions; 2216 } 2217 inline const _Internal_task_options & _get_internal_task_options(const task_options &options) 2218 { 2219 return options._M_InternalTaskOptions; 2220 } 2221 #endif 2222 struct _Task_impl_base; 2223 template<typename _ReturnType> struct _Task_impl; 2224 2225 template<typename _ReturnType> 2226 struct _Task_ptr 2227 { 2228 typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type; 2229 #if _MSC_VER >= 1800 2230 static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler_arg) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct, _Scheduler_arg); } 2231 #else 2232 static _Type _Make(Concurrency::details::_CancellationTokenState * _Ct) { return std::make_shared<_Task_impl<_ReturnType>>(_Ct); } 2233 #endif 2234 }; 2235 #if _MSC_VER >= 1800 2236 typedef Concurrency::details::_TaskCollection_t::_TaskProcHandle_t _UnrealizedChore_t; 2237 typedef _UnrealizedChore_t _UnrealizedChore; 2238 typedef Concurrency::extensibility::scoped_critical_section_t scoped_lock; 2239 typedef Concurrency::extensibility::critical_section_t critical_section; 2240 typedef Concurrency::details::atomic_size_t atomic_size_t; 2241 #else 2242 typedef Concurrency::details::_UnrealizedChore _UnrealizedChore; 2243 typedef Concurrency::critical_section::scoped_lock scoped_lock; 2244 typedef Concurrency::critical_section critical_section; 2245 typedef volatile size_t atomic_size_t; 2246 #endif 2247 typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base; 2248 // The weak-typed base task handler for continuation tasks. 2249 struct _ContinuationTaskHandleBase : _UnrealizedChore 2250 { 2251 _ContinuationTaskHandleBase * _M_next; 2252 task_continuation_context _M_continuationContext; 2253 bool _M_isTaskBasedContinuation; 2254 2255 // This field gives inlining scheduling policy for current chore. 2256 _TaskInliningMode _M_inliningMode; 2257 2258 virtual _Task_ptr_base _GetTaskImplBase() const = 0; 2259 2260 _ContinuationTaskHandleBase() : 2261 _M_next(nullptr), _M_isTaskBasedContinuation(false), _M_continuationContext(task_continuation_context::use_default()), _M_inliningMode(Concurrency::details::_NoInline) 2262 { 2263 } 2264 virtual ~_ContinuationTaskHandleBase() {} 2265 }; 2266 #if _MSC_VER >= 1800 2267 #if _PPLTASK_ASYNC_LOGGING 2268 // GUID used for identifying causality logs from PPLTask 2269 const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE); 2270 2271 __declspec(selectany) volatile long _isCausalitySupported = 0; 2272 2273 inline bool _IsCausalitySupported() 2274 { 2275 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 2276 if (_isCausalitySupported == 0) 2277 { 2278 long _causality = 1; 2279 OSVERSIONINFOEX _osvi = {}; 2280 _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 2281 2282 // The Causality is supported on Windows version higher than Windows 8 2283 _osvi.dwMajorVersion = 6; 2284 _osvi.dwMinorVersion = 3; 2285 2286 DWORDLONG _conditionMask = 0; 2287 VER_SET_CONDITION(_conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); 2288 VER_SET_CONDITION(_conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); 2289 2290 if (::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask)) 2291 { 2292 _causality = 2; 2293 } 2294 2295 _isCausalitySupported = _causality; 2296 return _causality == 2; 2297 } 2298 2299 return _isCausalitySupported == 2 ? true : false; 2300 #else 2301 return true; 2302 #endif 2303 } 2304 2305 // Stateful logger rests inside task_impl_base. 2306 struct _TaskEventLogger 2307 { 2308 _Task_impl_base *_M_task; 2309 bool _M_scheduled; 2310 bool _M_taskPostEventStarted; 2311 2312 // Log before scheduling task 2313 void _LogScheduleTask(bool _isContinuation) 2314 { 2315 if (details::_IsCausalitySupported()) 2316 { 2317 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2318 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), 2319 _isContinuation ? "Concurrency::PPLTask::ScheduleContinuationTask" : "Concurrency::PPLTask::ScheduleTask", 0); 2320 _M_scheduled = true; 2321 } 2322 } 2323 2324 // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state. 2325 void _LogCancelTask() 2326 { 2327 if (details::_IsCausalitySupported()) 2328 { 2329 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2330 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel); 2331 2332 } 2333 } 2334 2335 // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run 2336 void _LogTaskCompleted(); 2337 2338 // Log when task body (which includes user lambda and other scheduling code) begin to run 2339 void _LogTaskExecutionStarted() { } 2340 2341 // Log when task body finish executing 2342 void _LogTaskExecutionCompleted() 2343 { 2344 if (_M_taskPostEventStarted && details::_IsCausalitySupported()) 2345 { 2346 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2347 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); 2348 } 2349 } 2350 2351 // Log right before user lambda being invoked 2352 void _LogWorkItemStarted() 2353 { 2354 if (details::_IsCausalitySupported()) 2355 { 2356 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2357 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); 2358 } 2359 } 2360 2361 // Log right after user lambda being invoked 2362 void _LogWorkItemCompleted() 2363 { 2364 if (details::_IsCausalitySupported()) 2365 { 2366 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2367 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution); 2368 2369 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 2370 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification); 2371 _M_taskPostEventStarted = true; 2372 } 2373 } 2374 2375 _TaskEventLogger(_Task_impl_base *_task) : _M_task(_task) 2376 { 2377 _M_scheduled = false; 2378 _M_taskPostEventStarted = false; 2379 } 2380 }; 2381 2382 // Exception safe logger for user lambda 2383 struct _TaskWorkItemRAIILogger 2384 { 2385 _TaskEventLogger &_M_logger; 2386 _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger) : _M_logger(_taskHandleLogger) 2387 { 2388 _M_logger._LogWorkItemStarted(); 2389 } 2390 2391 ~_TaskWorkItemRAIILogger() 2392 { 2393 _M_logger._LogWorkItemCompleted(); 2394 } 2395 _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned 2396 }; 2397 2398 #else 2399 inline void _LogCancelTask(_Task_impl_base *) {} 2400 struct _TaskEventLogger 2401 { 2402 void _LogScheduleTask(bool) {} 2403 void _LogCancelTask() {} 2404 void _LogWorkItemStarted() {} 2405 void _LogWorkItemCompleted() {} 2406 void _LogTaskExecutionStarted() {} 2407 void _LogTaskExecutionCompleted() {} 2408 void _LogTaskCompleted() {} 2409 _TaskEventLogger(_Task_impl_base *) {} 2410 }; 2411 struct _TaskWorkItemRAIILogger 2412 { 2413 _TaskWorkItemRAIILogger(_TaskEventLogger &) {} 2414 }; 2415 #endif 2416 #endif 2417 /// <summary> 2418 /// The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped in this task handler 2419 /// to be executable by PPL. By deriving from a different _BaseTaskHandle, it can be used for both initial tasks and continuation tasks. 2420 /// For initial tasks, _PPLTaskHandle will be derived from _UnrealizedChore, and for continuation tasks, it will be derived from 2421 /// _ContinuationTaskHandleBase. The life time of the _PPLTaskHandle object is be managed by runtime if task handle is scheduled. 2422 /// </summary> 2423 /// <typeparam name="_ReturnType"> 2424 /// The result type of the _Task_impl. 2425 /// </typeparam> 2426 /// <typeparam name="_DerivedTaskHandle"> 2427 /// The derived task handle class. The <c>operator ()</c> needs to be implemented. 2428 /// </typeparam> 2429 /// <typeparam name="_BaseTaskHandle"> 2430 /// The base class from which _PPLTaskHandle should be derived. This is either _UnrealizedChore or _ContinuationTaskHandleBase. 2431 /// </typeparam> 2432 template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle> 2433 struct _PPLTaskHandle : _BaseTaskHandle 2434 { 2435 _PPLTaskHandle(const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask) 2436 { 2437 #if _MSC_VER < 1800 2438 m_pFunction = reinterpret_cast <Concurrency::TaskProc> (&_UnrealizedChore::_InvokeBridge<_PPLTaskHandle>); 2439 _SetRuntimeOwnsLifetime(true); 2440 #endif 2441 } 2442 virtual ~_PPLTaskHandle() { 2443 #if _MSC_VER >= 1800 2444 // Here is the sink of all task completion code paths 2445 _M_pTask->_M_taskEventLogger._LogTaskCompleted(); 2446 #endif 2447 } 2448 #if _MSC_VER >= 1800 2449 virtual void invoke() const 2450 #else 2451 void operator()() const 2452 #endif 2453 { 2454 // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled 2455 // by the runtime. 2456 _CONCRT_ASSERT(_M_pTask != nullptr); 2457 if (!_M_pTask->_TransitionedToStarted()) { 2458 #if _MSC_VER >= 1800 2459 static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException(); 2460 #endif 2461 return; 2462 } 2463 #if _MSC_VER >= 1800 2464 _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted(); 2465 #endif 2466 try 2467 { 2468 // All derived task handle must implement this contract function. 2469 static_cast<const _DerivedTaskHandle *>(this)->_Perform(); 2470 } 2471 catch (const Concurrency::task_canceled &) 2472 { 2473 _M_pTask->_Cancel(true); 2474 #if _MSC_VER < 1800 2475 throw; 2476 #endif 2477 } 2478 catch (const Concurrency::details::_Interruption_exception &) 2479 { 2480 _M_pTask->_Cancel(true); 2481 #if _MSC_VER < 1800 2482 throw; 2483 #endif 2484 } 2485 catch (IRestrictedErrorInfo*& _E) 2486 { 2487 _M_pTask->_CancelWithException(_E); 2488 #if _MSC_VER < 1800 2489 throw; 2490 #endif 2491 } 2492 catch (...) 2493 { 2494 _M_pTask->_CancelWithException(std::current_exception()); 2495 #if _MSC_VER < 1800 2496 throw; 2497 #endif 2498 } 2499 #if _MSC_VER >= 1800 2500 _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted(); 2501 #endif 2502 } 2503 2504 // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase. 2505 // The return value should be automatically optimized by R-value ref. 2506 _Task_ptr_base _GetTaskImplBase() const 2507 { 2508 return _M_pTask; 2509 } 2510 2511 typename _Task_ptr<_ReturnType>::_Type _M_pTask; 2512 2513 private: 2514 _PPLTaskHandle const & operator=(_PPLTaskHandle const&); // no assignment operator 2515 }; 2516 2517 /// <summary> 2518 /// The base implementation of a first-class task. This class contains all the non-type specific 2519 /// implementation details of the task. 2520 /// </summary> 2521 /**/ 2522 struct _Task_impl_base 2523 { 2524 enum _TaskInternalState 2525 { 2526 // Tracks the state of the task, rather than the task collection on which the task is scheduled 2527 _Created, 2528 _Started, 2529 _PendingCancel, 2530 _Completed, 2531 _Canceled 2532 }; 2533 #if _MSC_VER >= 1800 2534 _Task_impl_base(Concurrency::details::_CancellationTokenState * _PTokenState, Concurrency::scheduler_ptr _Scheduler_arg) 2535 : _M_TaskState(_Created), 2536 _M_fFromAsync(false), _M_fUnwrappedTask(false), 2537 _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg), 2538 _M_taskEventLogger(this) 2539 #else 2540 _Task_impl_base(Concurrency::details::_CancellationTokenState * _PTokenState) : _M_TaskState(_Created), 2541 _M_fFromAsync(false), _M_fRuntimeAggregate(false), _M_fUnwrappedTask(false), 2542 _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_pTaskCollection(nullptr), 2543 _M_pTaskCreationAddressHint(nullptr) 2544 #endif 2545 { 2546 // Set cancelation token 2547 _M_pTokenState = _PTokenState; 2548 _CONCRT_ASSERT(_M_pTokenState != nullptr); 2549 if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None()) 2550 _M_pTokenState->_Reference(); 2551 2552 } 2553 2554 virtual ~_Task_impl_base() 2555 { 2556 _CONCRT_ASSERT(_M_pTokenState != nullptr); 2557 if (_M_pTokenState != Concurrency::details::_CancellationTokenState::_None()) 2558 { 2559 _M_pTokenState->_Release(); 2560 } 2561 #if _MSC_VER < 1800 2562 if (_M_pTaskCollection != nullptr) 2563 { 2564 _M_pTaskCollection->_Release(); 2565 _M_pTaskCollection = nullptr; 2566 } 2567 #endif 2568 } 2569 2570 task_status _Wait() 2571 { 2572 bool _DoWait = true; 2573 2574 if (_IsNonBlockingThread()) 2575 { 2576 // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal 2577 // if task has not been completed. 2578 if (!_IsCompleted() && !_IsCanceled()) 2579 { 2580 throw Concurrency::invalid_operation("Illegal to wait on a task in a Windows Runtime STA"); 2581 } 2582 else 2583 { 2584 // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation 2585 // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM 2586 // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which 2587 // task based continuations are wont to do), waiting on the task group results in on the chore that is making this 2588 // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on 2589 // if it has finished execution (which means now we are on the inline synchronous callback). 2590 _DoWait = false; 2591 } 2592 } 2593 if (_DoWait) 2594 { 2595 #if _MSC_VER < 1800 2596 // Wait for the task to be actually scheduled, otherwise the underlying task collection 2597 // might not be created yet. If we don't wait, we will miss the chance to inline this task. 2598 _M_Scheduled.wait(); 2599 2600 2601 // A PPL task created by a task_completion_event does not have an underlying TaskCollection. For 2602 // These tasks, a call to wait should wait for the event to be set. The TaskCollection must either 2603 // be nullptr or allocated (the setting of _M_Scheduled) ensures that. 2604 #endif 2605 // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The 2606 // async operation will take place on a thread in the appropriate apartment Simply wait for the completed 2607 // event to be set. 2608 #if _MSC_VER >= 1800 2609 if (_M_fFromAsync) 2610 #else 2611 if ((_M_pTaskCollection == nullptr) || _M_fFromAsync) 2612 #endif 2613 { 2614 #if _MSC_VER >= 1800 2615 _M_TaskCollection._Wait(); 2616 #else 2617 _M_Completed.wait(); 2618 #endif 2619 } 2620 else 2621 { 2622 // Wait on the task collection to complete. The task collection is guaranteed to still be 2623 // valid since the task must be still within scope so that the _Task_impl_base destructor 2624 // has not yet been called. This call to _Wait potentially inlines execution of work. 2625 try 2626 { 2627 // Invoking wait on a task collection resets the state of the task collection. This means that 2628 // if the task collection itself were canceled, or had encountered an exception, only the first 2629 // call to wait will receive this status. However, both cancellation and exceptions flowing through 2630 // tasks set state in the task impl itself. 2631 2632 // When it returns cancelled, either work chore or the cancel thread should already have set task's state 2633 // properly -- cancelled state or completed state (because there was no interruption point). 2634 // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running. 2635 #if _MSC_VER >= 1800 2636 _M_TaskCollection._RunAndWait(); 2637 #else 2638 _M_pTaskCollection->_RunAndWait(); 2639 #endif 2640 } 2641 catch (Concurrency::details::_Interruption_exception&) 2642 { 2643 // The _TaskCollection will never be an interruption point since it has a none token. 2644 _CONCRT_ASSERT(false); 2645 } 2646 catch (Concurrency::task_canceled&) 2647 { 2648 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task 2649 // must be called from code that is executed within the task (throwing it from parallel work created by and waited 2650 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen 2651 // the exception and canceled the task. Swallow the exception here. 2652 _CONCRT_ASSERT(_IsCanceled()); 2653 } 2654 catch (IRestrictedErrorInfo*& _E) 2655 { 2656 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here. 2657 if(!_HasUserException()) 2658 { 2659 _CancelWithException(_E); 2660 } 2661 // Rethrow will mark the exception as observed. 2662 _M_exceptionHolder->_RethrowUserException(); 2663 } 2664 catch (...) 2665 { 2666 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here. 2667 if (!_HasUserException()) 2668 { 2669 _CancelWithException(std::current_exception()); 2670 } 2671 // Rethrow will mark the exception as observed. 2672 _M_exceptionHolder->_RethrowUserException(); 2673 } 2674 2675 // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task 2676 // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must 2677 // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through; 2678 // however, this takes the tact of simply waiting upon the completion signal. 2679 if (_M_fUnwrappedTask) 2680 { 2681 #if _MSC_VER >= 1800 2682 _M_TaskCollection._Wait(); 2683 #else 2684 _M_Completed.wait(); 2685 #endif 2686 } 2687 } 2688 } 2689 2690 if (_HasUserException()) 2691 { 2692 _M_exceptionHolder->_RethrowUserException(); 2693 } 2694 else if (_IsCanceled()) 2695 { 2696 return Concurrency::canceled; 2697 } 2698 _CONCRT_ASSERT(_IsCompleted()); 2699 return Concurrency::completed; 2700 } 2701 /// <summary> 2702 /// Requests cancellation on the task and schedules continuations if the task can be transitioned to a terminal state. 2703 /// </summary> 2704 /// <param name="_SynchronousCancel"> 2705 /// Set to true if the cancel takes place as a result of the task body encountering an exception, or because an ancestor or task_completion_event the task 2706 /// was registered with were canceled with an exception. A synchronous cancel is one that assures the task could not be running on a different thread at 2707 /// the time the cancellation is in progress. An asynchronous cancel is one where the thread performing the cancel has no control over the thread that could 2708 /// be executing the task, that is the task could execute concurrently while the cancellation is in progress. 2709 /// </param> 2710 /// <param name="_UserException"> 2711 /// Whether an exception other than the internal runtime cancellation exceptions caused this cancellation. 2712 /// </param> 2713 /// <param name="_PropagatedFromAncestor"> 2714 /// Whether this exception came from an ancestor task or a task_completion_event as opposed to an exception that was encountered by the task itself. Only valid when 2715 /// _UserException is set to true. 2716 /// </param> 2717 /// <param name="_ExHolder"> 2718 /// The exception holder that represents the exception. Only valid when _UserException is set to true. 2719 /// </param> 2720 virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0; 2721 2722 bool _Cancel(bool _SynchronousCancel) 2723 { 2724 // Send in a dummy value for exception. It is not used when the first parameter is false. 2725 return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder); 2726 } 2727 2728 bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor) 2729 { 2730 // This task was canceled because an ancestor task encountered an exception. 2731 return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder); 2732 } 2733 2734 bool _CancelWithException(IRestrictedErrorInfo*& _Exception) 2735 { 2736 // This task was canceled because the task body encountered an exception. 2737 _CONCRT_ASSERT(!_HasUserException()); 2738 #if _MSC_VER >= 1800 2739 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); 2740 #else 2741 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint())); 2742 #endif 2743 } 2744 bool _CancelWithException(const std::exception_ptr& _Exception) 2745 { 2746 // This task was canceled because the task body encountered an exception. 2747 _CONCRT_ASSERT(!_HasUserException()); 2748 #if _MSC_VER >= 1800 2749 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack())); 2750 #else 2751 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationAddressHint())); 2752 #endif 2753 } 2754 2755 #if _MSC_VER >= 1800 2756 void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr) 2757 #else 2758 void _RegisterCancellation() 2759 #endif 2760 { 2761 _CONCRT_ASSERT(Concurrency::details::_CancellationTokenState::_IsValid(_M_pTokenState)); 2762 #if _MSC_VER >= 1800 2763 auto _CancellationCallback = [_WeakPtr](){ 2764 // Taking ownership of the task prevents dead lock during destruction 2765 // if the destructor waits for the cancellations to be finished 2766 auto _task = _WeakPtr.lock(); 2767 if (_task != nullptr) 2768 _task->_Cancel(false); 2769 }; 2770 2771 _M_pRegistration = new Concurrency::details::_CancellationTokenCallback<decltype(_CancellationCallback)>(_CancellationCallback); 2772 _M_pTokenState->_RegisterCallback(_M_pRegistration); 2773 #else 2774 _M_pRegistration = _M_pTokenState->_RegisterCallback(reinterpret_cast<Concurrency::TaskProc>(&_CancelViaToken), (_Task_impl_base *)this); 2775 #endif 2776 } 2777 2778 void _DeregisterCancellation() 2779 { 2780 if (_M_pRegistration != nullptr) 2781 { 2782 _M_pTokenState->_DeregisterCallback(_M_pRegistration); 2783 _M_pRegistration->_Release(); 2784 _M_pRegistration = nullptr; 2785 } 2786 } 2787 #if _MSC_VER < 1800 2788 static void _CancelViaToken(_Task_impl_base *_PImpl) 2789 { 2790 _PImpl->_Cancel(false); 2791 } 2792 #endif 2793 bool _IsCreated() 2794 { 2795 return (_M_TaskState == _Created); 2796 } 2797 2798 bool _IsStarted() 2799 { 2800 return (_M_TaskState == _Started); 2801 } 2802 2803 bool _IsPendingCancel() 2804 { 2805 return (_M_TaskState == _PendingCancel); 2806 } 2807 2808 bool _IsCompleted() 2809 { 2810 return (_M_TaskState == _Completed); 2811 } 2812 2813 bool _IsCanceled() 2814 { 2815 return (_M_TaskState == _Canceled); 2816 } 2817 2818 bool _HasUserException() 2819 { 2820 return static_cast<bool>(_M_exceptionHolder); 2821 } 2822 #if _MSC_VER < 1800 2823 void _SetScheduledEvent() 2824 { 2825 _M_Scheduled.set(); 2826 } 2827 #endif 2828 const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder() 2829 { 2830 _CONCRT_ASSERT(_HasUserException()); 2831 return _M_exceptionHolder; 2832 } 2833 2834 bool _IsApartmentAware() 2835 { 2836 return _M_fFromAsync; 2837 } 2838 2839 void _SetAsync(bool _Async = true) 2840 { 2841 _M_fFromAsync = _Async; 2842 } 2843 #if _MSC_VER >= 1800 2844 _TaskCreationCallstack _GetTaskCreationCallstack() 2845 { 2846 return _M_pTaskCreationCallstack; 2847 } 2848 2849 void _SetTaskCreationCallstack(const _TaskCreationCallstack &_Callstack) 2850 { 2851 _M_pTaskCreationCallstack = _Callstack; 2852 } 2853 #else 2854 void* _GetTaskCreationAddressHint() 2855 { 2856 return _M_pTaskCreationAddressHint; 2857 } 2858 2859 void _SetTaskCreationAddressHint(void* _AddressHint) 2860 { 2861 _M_pTaskCreationAddressHint = _AddressHint; 2862 } 2863 #endif 2864 /// <summary> 2865 /// Helper function to schedule the task on the Task Collection. 2866 /// </summary> 2867 /// <param name="_PTaskHandle"> 2868 /// The task chore handle that need to be executed. 2869 /// </param> 2870 /// <param name="_InliningMode"> 2871 /// The inlining scheduling policy for current _PTaskHandle. 2872 /// </param> 2873 void _ScheduleTask(_UnrealizedChore * _PTaskHandle, _TaskInliningMode _InliningMode) 2874 { 2875 #if _MSC_VER < 1800 2876 // Construct the task collection; We use none token to provent it becoming interruption point. 2877 _M_pTaskCollection = Concurrency::details::_AsyncTaskCollection::_NewCollection(Concurrency::details::_CancellationTokenState::_None()); 2878 // _M_pTaskCollection->_ScheduleWithAutoInline will schedule the chore onto AsyncTaskCollection with automatic inlining, in a way that honors cancellation etc. 2879 #endif 2880 try 2881 { 2882 #if _MSC_VER >= 1800 2883 _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode); 2884 #else 2885 // Do not need to check its returning state, more details please refer to _Wait method. 2886 _M_pTaskCollection->_ScheduleWithAutoInline(_PTaskHandle, _InliningMode); 2887 #endif 2888 } 2889 catch (const Concurrency::task_canceled &) 2890 { 2891 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task 2892 // must be called from code that is executed within the task (throwing it from parallel work created by and waited 2893 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen 2894 // the exception and canceled the task. Swallow the exception here. 2895 _CONCRT_ASSERT(_IsCanceled()); 2896 } 2897 catch (const Concurrency::details::_Interruption_exception &) 2898 { 2899 // The _TaskCollection will never be an interruption point since it has a none token. 2900 _CONCRT_ASSERT(false); 2901 } 2902 catch (...) 2903 { 2904 // This exception could only have come from within the chore body. It should've been caught 2905 // and the task should be canceled with exception. Swallow the exception here. 2906 _CONCRT_ASSERT(_HasUserException()); 2907 } 2908 #if _MSC_VER < 1800 2909 // Set the event in case anyone is waiting to notify that this task has been scheduled. In the case where we 2910 // execute the chore inline, the event should be set after the chore has executed, to prevent a different thread 2911 // performing a wait on the task from waiting on the task collection before the chore is actually added to it, 2912 // and thereby returning from the wait() before the chore has executed. 2913 _SetScheduledEvent(); 2914 #endif 2915 } 2916 2917 /// <summary> 2918 /// Function executes a continuation. This function is recorded by a parent task implementation 2919 /// when a continuation is created in order to execute later. 2920 /// </summary> 2921 /// <param name="_PTaskHandle"> 2922 /// The continuation task chore handle that need to be executed. 2923 /// </param> 2924 /**/ 2925 void _RunContinuation(_ContinuationTaskHandleBase * _PTaskHandle) 2926 { 2927 _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase(); 2928 if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation) 2929 { 2930 if (_HasUserException()) 2931 { 2932 // If the ancestor encountered an exception, transfer the exception to the continuation 2933 // This traverses down the tree to propagate the exception. 2934 _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true); 2935 } 2936 else 2937 { 2938 // If the ancestor was canceled, then your own execution should be canceled. 2939 // This traverses down the tree to cancel it. 2940 _ImplBase->_Cancel(true); 2941 } 2942 } 2943 else 2944 { 2945 // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled 2946 // (with or without a user exception). 2947 _CONCRT_ASSERT(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation); 2948 2949 #if _MSC_VER >= 1800 2950 _CONCRT_ASSERT(!_ImplBase->_IsCanceled()); 2951 return _ImplBase->_ScheduleContinuationTask(_PTaskHandle); 2952 #else 2953 // If it has been canceled here (before starting), do nothing. The guy firing cancel will do the clean up. 2954 if (!_ImplBase->_IsCanceled()) 2955 { 2956 return _ImplBase->_ScheduleContinuationTask(_PTaskHandle); 2957 } 2958 #endif 2959 } 2960 2961 // If the handle is not scheduled, we need to manually delete it. 2962 delete _PTaskHandle; 2963 } 2964 2965 // Schedule a continuation to run 2966 void _ScheduleContinuationTask(_ContinuationTaskHandleBase * _PTaskHandle) 2967 { 2968 #if _MSC_VER >= 1800 2969 _M_taskEventLogger._LogScheduleTask(true); 2970 #endif 2971 // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment) 2972 if (_PTaskHandle->_M_continuationContext._HasCapturedContext()) 2973 { 2974 // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes, 2975 // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce 2976 // the cost of marshaling. 2977 // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method. 2978 if (_PTaskHandle->_M_inliningMode != Concurrency::details::_ForceInline) 2979 { 2980 _PTaskHandle->_M_inliningMode = Concurrency::details::_DefaultAutoInline; 2981 } 2982 details::_ScheduleFuncWithAutoInline([_PTaskHandle]() -> HRESULT { 2983 // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base. 2984 // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled. 2985 auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase(); 2986 if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext) 2987 { 2988 _TaskImplPtr->_ScheduleTask(_PTaskHandle, Concurrency::details::_ForceInline); 2989 } 2990 else 2991 { 2992 // 2993 // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle 2994 // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this: 2995 // 2996 // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into 2997 // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will 2998 // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...). 2999 // 3000 try 3001 { 3002 // Dev10 compiler needs this! 3003 auto _PTaskHandle1 = _PTaskHandle; 3004 _PTaskHandle->_M_continuationContext._CallInContext([_PTaskHandle1, _TaskImplPtr]() -> HRESULT { 3005 _TaskImplPtr->_ScheduleTask(_PTaskHandle1, Concurrency::details::_ForceInline); 3006 return S_OK; 3007 }); 3008 } 3009 catch (IRestrictedErrorInfo*& _E) 3010 { 3011 _TaskImplPtr->_CancelWithException(_E); 3012 } 3013 catch (...) 3014 { 3015 _TaskImplPtr->_CancelWithException(std::current_exception()); 3016 } 3017 } 3018 return S_OK; 3019 }, _PTaskHandle->_M_inliningMode); 3020 } 3021 else 3022 { 3023 _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode); 3024 } 3025 } 3026 3027 /// <summary> 3028 /// Schedule the actual continuation. This will either schedule the function on the continuation task's implementation 3029 /// if the task has completed or append it to a list of functions to execute when the task actually does complete. 3030 /// </summary> 3031 /// <typeparam name="_FuncInputType"> 3032 /// The input type of the task. 3033 /// </typeparam> 3034 /// <typeparam name="_FuncOutputType"> 3035 /// The output type of the task. 3036 /// </typeparam> 3037 /**/ 3038 void _ScheduleContinuation(_ContinuationTaskHandleBase * _PTaskHandle) 3039 { 3040 enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing; 3041 3042 // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away. 3043 // Otherwise, add it to the list of pending continuations 3044 { 3045 scoped_lock _LockHolder(_M_ContinuationsCritSec); 3046 if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation)) 3047 { 3048 _Do = _Schedule; 3049 } 3050 else if (_IsCanceled()) 3051 { 3052 if (_HasUserException()) 3053 { 3054 _Do = _CancelWithException; 3055 } 3056 else 3057 { 3058 _Do = _Cancel; 3059 } 3060 } 3061 else 3062 { 3063 // chain itself on the continuation chain. 3064 _PTaskHandle->_M_next = _M_Continuations; 3065 _M_Continuations = _PTaskHandle; 3066 } 3067 } 3068 3069 // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of 3070 // async tasks may execute inline. 3071 switch (_Do) 3072 { 3073 case _Schedule: 3074 { 3075 _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle); 3076 break; 3077 } 3078 case _Cancel: 3079 { 3080 // If the ancestor was canceled, then your own execution should be canceled. 3081 // This traverses down the tree to cancel it. 3082 _PTaskHandle->_GetTaskImplBase()->_Cancel(true); 3083 3084 delete _PTaskHandle; 3085 break; 3086 } 3087 case _CancelWithException: 3088 { 3089 // If the ancestor encountered an exception, transfer the exception to the continuation 3090 // This traverses down the tree to propagate the exception. 3091 _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true); 3092 3093 delete _PTaskHandle; 3094 break; 3095 } 3096 case _Nothing: 3097 default: 3098 // In this case, we have inserted continuation to continuation chain, 3099 // nothing more need to be done, just leave. 3100 break; 3101 } 3102 } 3103 3104 void _RunTaskContinuations() 3105 { 3106 // The link list can no longer be modified at this point, 3107 // since all following up continuations will be scheduled by themselves. 3108 _ContinuationList _Cur = _M_Continuations, _Next; 3109 _M_Continuations = nullptr; 3110 while (_Cur) 3111 { 3112 // Current node might be deleted after running, 3113 // so we must fetch the next first. 3114 _Next = _Cur->_M_next; 3115 _RunContinuation(_Cur); 3116 _Cur = _Next; 3117 } 3118 } 3119 static bool _IsNonBlockingThread() 3120 { 3121 APTTYPE _AptType; 3122 APTTYPEQUALIFIER _AptTypeQualifier; 3123 3124 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier); 3125 // 3126 // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure. 3127 // 3128 if (SUCCEEDED(hr)) 3129 { 3130 switch (_AptType) 3131 { 3132 case APTTYPE_STA: 3133 case APTTYPE_MAINSTA: 3134 return true; 3135 break; 3136 case APTTYPE_NA: 3137 switch (_AptTypeQualifier) 3138 { 3139 // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed 3140 // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting 3141 // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the 3142 // thread out of circulation for a while. 3143 case APTTYPEQUALIFIER_NA_ON_STA: 3144 case APTTYPEQUALIFIER_NA_ON_MAINSTA: 3145 return true; 3146 break; 3147 } 3148 break; 3149 } 3150 } 3151 #if _UITHREADCTXT_SUPPORT 3152 // This method is used to throw an exepection in _Wait() if called within STA. We 3153 // want the same behavior if _Wait is called on the UI thread. 3154 if (SUCCEEDED(CaptureUiThreadContext(nullptr))) 3155 { 3156 return true; 3157 } 3158 #endif // _UITHREADCTXT_SUPPORT 3159 3160 return false; 3161 } 3162 3163 template<typename _ReturnType, typename _Result, typename _OpType, typename _CompHandlerType, typename _ResultType> 3164 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask, 3165 _AsyncInfoImpl<_OpType, _CompHandlerType, _ResultType>* _AsyncOp) 3166 { 3167 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_GetUnwrappedType(stdx::declval<_OpType*>()))>::type _Result_abi; 3168 // This method is invoked either when a task is created from an existing async operation or 3169 // when a lambda that creates an async operation executes. 3170 3171 // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on 3172 // the IAsyncInfo object will be released when all *references to the operation go out of scope. 3173 3174 // This assertion uses the existence of taskcollection to determine if the task was created from an event. 3175 // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection 3176 // when a custom scheduler is used. 3177 #if _MSC_VER < 1800 3178 _CONCRT_ASSERT(((_OuterTask->_M_pTaskCollection == nullptr) || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled()); 3179 #endif 3180 3181 // Pass the shared_ptr by value into the lambda instead of using 'this'. 3182 3183 _AsyncOp->put_Completed(Microsoft::WRL::Callback<_CompHandlerType>( 3184 [_OuterTask, _AsyncOp](_OpType* _Operation, ABI::Windows::Foundation::AsyncStatus _Status) mutable -> HRESULT 3185 { 3186 HRESULT hr = S_OK; 3187 if (_Status == ABI::Windows::Foundation::AsyncStatus::Canceled) 3188 { 3189 _OuterTask->_Cancel(true); 3190 } 3191 else if (_Status == ABI::Windows::Foundation::AsyncStatus::Error) 3192 { 3193 HRESULT _hr; 3194 Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> pAsyncInfo; 3195 if (SUCCEEDED(hr = _Operation->QueryInterface<ABI::Windows::Foundation::IAsyncInfo>(pAsyncInfo.GetAddressOf())) && SUCCEEDED(hr = pAsyncInfo->get_ErrorCode(&_hr))) 3196 _OuterTask->_CancelWithException(std::make_exception_ptr(_hr)); 3197 } 3198 else 3199 { 3200 _CONCRT_ASSERT(_Status == ABI::Windows::Foundation::AsyncStatus::Completed); 3201 _NormalizeVoidToUnitType<_Result_abi>::_Type results; 3202 if (SUCCEEDED(hr = _AsyncOp->GetResults(&results))) 3203 _OuterTask->_FinalizeAndRunContinuations(results); 3204 } 3205 // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could 3206 // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold 3207 // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from 3208 // it using the Windows Runtime Async APIs causes a sharing violation. 3209 // Using const_cast is the workaround for failed mutable keywords 3210 const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset(); 3211 return hr; 3212 }).Get()); 3213 _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp); 3214 } 3215 template<typename _ReturnType, typename _InternalReturnType> 3216 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask) 3217 { 3218 _CONCRT_ASSERT(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled()); 3219 // 3220 // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the 3221 // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation 3222 // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent 3223 // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless 3224 // of whether or not the _OuterTask task is canceled. 3225 // 3226 _UnwrappedTask._Then([_OuterTask](task<_InternalReturnType> _AncestorTask) -> HRESULT { 3227 3228 if (_AncestorTask._GetImpl()->_IsCompleted()) 3229 { 3230 _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult()); 3231 } 3232 else 3233 { 3234 _CONCRT_ASSERT(_AncestorTask._GetImpl()->_IsCanceled()); 3235 if (_AncestorTask._GetImpl()->_HasUserException()) 3236 { 3237 // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask. 3238 // Instead, it is the enclosing task. 3239 _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false); 3240 } 3241 else 3242 { 3243 _OuterTask->_Cancel(true); 3244 } 3245 } 3246 return S_OK; 3247 #if _MSC_VER >= 1800 3248 }, nullptr, Concurrency::details::_DefaultAutoInline); 3249 #else 3250 }, nullptr, false, Concurrency::details::_DefaultAutoInline); 3251 #endif 3252 } 3253 3254 #if _MSC_VER >= 1800 3255 Concurrency::scheduler_ptr _GetScheduler() const 3256 { 3257 return _M_TaskCollection._GetScheduler(); 3258 } 3259 #else 3260 Concurrency::event _M_Completed; 3261 Concurrency::event _M_Scheduled; 3262 #endif 3263 3264 // Tracks the internal state of the task 3265 volatile _TaskInternalState _M_TaskState; 3266 // Set to true either if the ancestor task had the flag set to true, or if the lambda that does the work of this task returns an 3267 // async operation or async action that is unwrapped by the runtime. 3268 bool _M_fFromAsync; 3269 #if _MSC_VER < 1800 3270 // Set to true if we need to marshal the inner parts of an aggregate type like std::vector<T^> or std::pair<T^, size_t>. We only marshal 3271 // the contained T^s if we create the vector or pair, such as on a when_any or a when_all operation. 3272 bool _M_fRuntimeAggregate; 3273 #endif 3274 // Set to true when a continuation unwraps a task or async operation. 3275 bool _M_fUnwrappedTask; 3276 3277 // An exception thrown by the task body is captured in an exception holder and it is shared with all value based continuations rooted at the task. 3278 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception 3279 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast. 3280 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; 3281 3282 typedef _ContinuationTaskHandleBase * _ContinuationList; 3283 3284 critical_section _M_ContinuationsCritSec; 3285 _ContinuationList _M_Continuations; 3286 3287 // The cancellation token state. 3288 Concurrency::details::_CancellationTokenState * _M_pTokenState; 3289 3290 // The registration on the token. 3291 Concurrency::details::_CancellationTokenRegistration * _M_pRegistration; 3292 3293 // The async task collection wrapper 3294 #if _MSC_VER >= 1800 3295 Concurrency::details::_TaskCollection_t _M_TaskCollection; 3296 3297 // Callstack for function call (constructor or .then) that created this task impl. 3298 _TaskCreationCallstack _M_pTaskCreationCallstack; 3299 3300 _TaskEventLogger _M_taskEventLogger; 3301 #else 3302 Concurrency::details::_AsyncTaskCollection * _M_pTaskCollection; 3303 3304 // Points to the source code instruction right after the function call (constructor or .then) that created this task impl. 3305 void* _M_pTaskCreationAddressHint; 3306 #endif 3307 3308 private: 3309 // Must not be copied by value: 3310 _Task_impl_base(const _Task_impl_base&); 3311 _Task_impl_base const & operator=(_Task_impl_base const&); 3312 }; 3313 3314 #if _MSC_VER >= 1800 3315 #if _PPLTASK_ASYNC_LOGGING 3316 inline void _TaskEventLogger::_LogTaskCompleted() 3317 { 3318 if (_M_scheduled) 3319 { 3320 ::Windows::Foundation::AsyncStatus _State; 3321 if (_M_task->_IsCompleted()) 3322 _State = ::Windows::Foundation::AsyncStatus::Completed; 3323 else if (_M_task->_HasUserException()) 3324 _State = ::Windows::Foundation::AsyncStatus::Error; 3325 else 3326 _State = ::Windows::Foundation::AsyncStatus::Canceled; 3327 3328 if (details::_IsCausalitySupported()) 3329 { 3330 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library, 3331 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State); 3332 } 3333 } 3334 } 3335 #endif 3336 #endif 3337 3338 template<typename _ReturnType> 3339 struct _Task_impl : public _Task_impl_base 3340 { 3341 typedef ABI::Windows::Foundation::IAsyncInfo _AsyncOperationType; 3342 #if _MSC_VER >= 1800 3343 _Task_impl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler_arg) 3344 : _Task_impl_base(_Ct, _Scheduler_arg) 3345 #else 3346 _Task_impl(Concurrency::details::_CancellationTokenState * _Ct) : _Task_impl_base(_Ct) 3347 #endif 3348 { 3349 _M_unwrapped_async_op = nullptr; 3350 } 3351 virtual ~_Task_impl() 3352 { 3353 // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause 3354 // a partially initialized _Task_impl to be in the list of registrations for a cancellation token. 3355 _DeregisterCancellation(); 3356 } 3357 virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder) 3358 { 3359 enum { _Nothing, _RunContinuations, _Cancel } _Do = _Nothing; 3360 { 3361 scoped_lock _LockHolder(_M_ContinuationsCritSec); 3362 if (_UserException) 3363 { 3364 _CONCRT_ASSERT(_SynchronousCancel && !_IsCompleted()); 3365 // If the state is _Canceled, the exception has to be coming from an ancestor. 3366 _CONCRT_ASSERT(!_IsCanceled() || _PropagatedFromAncestor); 3367 #if _MSC_VER < 1800 3368 // If the state is _Started or _PendingCancel, the exception cannot be coming from an ancestor. 3369 _CONCRT_ASSERT((!_IsStarted() && !_IsPendingCancel()) || !_PropagatedFromAncestor); 3370 #endif 3371 // We should not be canceled with an exception more than once. 3372 _CONCRT_ASSERT(!_HasUserException()); 3373 3374 if (_M_TaskState == _Canceled) 3375 { 3376 // If the task has finished cancelling there should not be any continuation records in the array. 3377 return false; 3378 } 3379 else 3380 { 3381 _CONCRT_ASSERT(_M_TaskState != _Completed); 3382 _M_exceptionHolder = _ExceptionHolder; 3383 } 3384 } 3385 else 3386 { 3387 // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel 3388 // which is to say, cancellation is already initiated, so return early. 3389 if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel)) 3390 { 3391 _CONCRT_ASSERT(!_IsCompleted() || !_HasUserException()); 3392 return false; 3393 } 3394 _CONCRT_ASSERT(!_SynchronousCancel || !_HasUserException()); 3395 } 3396 3397 #if _MSC_VER >= 1800 3398 if (_SynchronousCancel) 3399 #else 3400 if (_SynchronousCancel || _IsCreated()) 3401 #endif 3402 { 3403 // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait() 3404 _M_TaskState = _Canceled; 3405 #if _MSC_VER < 1800 3406 _M_Scheduled.set(); 3407 #endif 3408 3409 // Cancellation completes the task, so all dependent tasks must be run to cancel them 3410 // They are canceled when they begin running (see _RunContinuation) and see that their 3411 // ancestor has been canceled. 3412 _Do = _RunContinuations; 3413 } 3414 else 3415 { 3416 #if _MSC_VER >= 1800 3417 _CONCRT_ASSERT(!_UserException); 3418 3419 if (_IsStarted()) 3420 { 3421 // should not initiate cancellation under a lock 3422 _Do = _Cancel; 3423 } 3424 3425 // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore). 3426 // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from 3427 // _Started to _PendingCancel before it can move to _Canceled when it is finished executing. 3428 _M_TaskState = _PendingCancel; 3429 3430 _M_taskEventLogger._LogCancelTask(); 3431 } 3432 } 3433 3434 switch (_Do) 3435 { 3436 case _Cancel: 3437 { 3438 #else 3439 _CONCRT_ASSERT(_IsStarted() && !_UserException); 3440 #endif 3441 // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore). 3442 // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from 3443 // _Started to _PendingCancel before it can move to _Canceled when it is finished executing. 3444 _M_TaskState = _PendingCancel; 3445 if (_M_unwrapped_async_op != nullptr) 3446 { 3447 // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token. 3448 if (_M_unwrapped_async_op) _M_unwrapped_async_op->Cancel(); 3449 } 3450 #if _MSC_VER >= 1800 3451 _M_TaskCollection._Cancel(); 3452 break; 3453 #else 3454 // Optimistic trying for cancelation 3455 if (_M_pTaskCollection != nullptr) 3456 { 3457 _M_pTaskCollection->_Cancel(); 3458 } 3459 #endif 3460 } 3461 #if _MSC_VER < 1800 3462 } 3463 #endif 3464 3465 // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state. 3466 #if _MSC_VER >= 1800 3467 case _RunContinuations: 3468 { 3469 _M_TaskCollection._Complete(); 3470 #else 3471 if (_RunContinuations) 3472 { 3473 _M_Completed.set(); 3474 #endif 3475 3476 if (_M_Continuations) 3477 { 3478 // Scheduling cancellation with automatic inlining. 3479 details::_ScheduleFuncWithAutoInline([=]() -> HRESULT { _RunTaskContinuations(); return S_OK; }, Concurrency::details::_DefaultAutoInline); 3480 } 3481 #if _MSC_VER >= 1800 3482 break; 3483 } 3484 #endif 3485 } 3486 return true; 3487 } 3488 void _FinalizeAndRunContinuations(_ReturnType _Result) 3489 { 3490 3491 #if _MSC_VER >= 1800 3492 _M_Result.Set(_Result); 3493 #else 3494 _M_Result = _Result; 3495 _M_ResultContext = _ResultContext<_ReturnType>::_GetContext(_M_fRuntimeAggregate); 3496 #endif 3497 { 3498 // 3499 // Hold this lock to ensure continuations being concurrently either get added 3500 // to the _M_Continuations vector or wait for the result 3501 // 3502 scoped_lock _LockHolder(_M_ContinuationsCritSec); 3503 3504 // A task could still be in the _Created state if it was created with a task_completion_event. 3505 // It could also be in the _Canceled state for the same reason. 3506 _CONCRT_ASSERT(!_HasUserException() && !_IsCompleted()); 3507 if (_IsCanceled()) 3508 { 3509 return; 3510 } 3511 3512 // Always transition to "completed" state, even in the face of unacknowledged pending cancellation 3513 _M_TaskState = _Completed; 3514 } 3515 #if _MSC_VER >= 1800 3516 _M_TaskCollection._Complete(); 3517 #else 3518 _M_Completed.set(); 3519 #endif 3520 _RunTaskContinuations(); 3521 } 3522 // 3523 // This method is invoked when the starts executing. The task returns early if this method returns true. 3524 // 3525 bool _TransitionedToStarted() 3526 { 3527 scoped_lock _LockHolder(_M_ContinuationsCritSec); 3528 #if _MSC_VER >= 1800 3529 // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here. 3530 _ASSERT(!_IsCanceled()); 3531 if (_IsPendingCancel()) 3532 #else 3533 if (_IsCanceled()) 3534 #endif 3535 { 3536 return false; 3537 } 3538 _CONCRT_ASSERT(_IsCreated()); 3539 _M_TaskState = _Started; 3540 return true; 3541 } 3542 void _SetUnwrappedAsyncOp(_AsyncOperationType* _AsyncOp) 3543 { 3544 scoped_lock _LockHolder(_M_ContinuationsCritSec); 3545 // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it. 3546 if (_IsPendingCancel()) 3547 { 3548 _CONCRT_ASSERT(!_IsCanceled()); 3549 if (_AsyncOp) _AsyncOp->Cancel(); 3550 } 3551 else 3552 { 3553 _M_unwrapped_async_op = _AsyncOp; 3554 } 3555 } 3556 #if _MSC_VER >= 1800 3557 // Return true if the task has reached a terminal state 3558 bool _IsDone() 3559 { 3560 return _IsCompleted() || _IsCanceled(); 3561 } 3562 #endif 3563 _ReturnType _GetResult() 3564 { 3565 #if _MSC_VER >= 1800 3566 return _M_Result.Get(); 3567 #else 3568 return _ResultContext<_ReturnType>::_GetValue(_M_Result, _M_ResultContext, _M_fRuntimeAggregate); 3569 #endif 3570 } 3571 #if _MSC_VER >= 1800 3572 _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor. 3573 #else 3574 _ReturnType _M_Result; // this means that the result type must have a public default ctor. 3575 #endif 3576 Microsoft::WRL::ComPtr<_AsyncOperationType> _M_unwrapped_async_op; 3577 #if _MSC_VER < 1800 3578 _ContextCallback _M_ResultContext; 3579 #endif 3580 }; 3581 3582 template<typename _ResultType> 3583 struct _Task_completion_event_impl 3584 { 3585 #if _MSC_VER >= 1800 3586 private: 3587 _Task_completion_event_impl(const _Task_completion_event_impl&); 3588 _Task_completion_event_impl& operator=(const _Task_completion_event_impl&); 3589 3590 public: 3591 #endif 3592 typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList; 3593 3594 _Task_completion_event_impl() : _M_fHasValue(false), _M_fIsCanceled(false) 3595 { 3596 } 3597 3598 bool _HasUserException() 3599 { 3600 return _M_exceptionHolder != nullptr; 3601 } 3602 3603 ~_Task_completion_event_impl() 3604 { 3605 for (auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt) 3606 { 3607 _CONCRT_ASSERT(!_M_fHasValue && !_M_fIsCanceled); 3608 // Cancel the tasks since the event was never signaled or canceled. 3609 (*_TaskIt)->_Cancel(true); 3610 } 3611 } 3612 3613 // We need to protect the loop over the array, so concurrent_vector would not have helped 3614 _TaskList _M_tasks; 3615 critical_section _M_taskListCritSec; 3616 #if _MSC_VER >= 1800 3617 _ResultHolder<_ResultType> _M_value; 3618 #else 3619 _ResultType _M_value; 3620 #endif 3621 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder; 3622 bool _M_fHasValue; 3623 bool _M_fIsCanceled; 3624 }; 3625 3626 // Utility method for dealing with void functions 3627 inline std::function<HRESULT(_Unit_type*)> _MakeVoidToUnitFunc(const std::function<HRESULT(void)>& _Func) 3628 { 3629 return [=](_Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; }; 3630 } 3631 3632 template <typename _Type> 3633 std::function<HRESULT(_Unit_type, _Type*)> _MakeUnitToTFunc(const std::function<HRESULT(_Type*)>& _Func) 3634 { 3635 return [=](_Unit_type, _Type* retVal) -> HRESULT { HRESULT hr = _Func(retVal); return hr; }; 3636 } 3637 3638 template <typename _Type> 3639 std::function<HRESULT(_Type, _Unit_type*)> _MakeTToUnitFunc(const std::function<HRESULT(_Type)>& _Func) 3640 { 3641 return[=](_Type t, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(t); *retVal = _Unit_type(); return hr; }; 3642 } 3643 3644 inline std::function<HRESULT(_Unit_type, _Unit_type*)> _MakeUnitToUnitFunc(const std::function<HRESULT(void)>& _Func) 3645 { 3646 return [=](_Unit_type, _Unit_type* retVal) -> HRESULT { HRESULT hr = _Func(); *retVal = _Unit_type(); return hr; }; 3647 } 3648 } 3649 3650 3651 /// <summary> 3652 /// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied, 3653 /// or start a task in response to an external event. 3654 /// </summary> 3655 /// <typeparam name="_ResultType"> 3656 /// The result type of this <c>task_completion_event</c> class. 3657 /// </typeparam> 3658 /// <remarks> 3659 /// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and 3660 /// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must 3661 /// have the same type as the task you create, and calling the set method on the task completion event with a value of that type 3662 /// will cause the associated task to complete, and provide that value as a result to its continuations. 3663 /// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para> 3664 /// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para> 3665 /// </remarks> 3666 /// <seealso cref="task Class"/> 3667 /**/ 3668 template<typename _ResultType> 3669 class task_completion_event 3670 { 3671 public: 3672 /// <summary> 3673 /// Constructs a <c>task_completion_event</c> object. 3674 /// </summary> 3675 /**/ 3676 task_completion_event() : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>()) 3677 { 3678 } 3679 3680 /// <summary> 3681 /// Sets the task completion event. 3682 /// </summary> 3683 /// <param name="_Result"> 3684 /// The result to set this event with. 3685 /// </param> 3686 /// <returns> 3687 /// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set. 3688 /// </returns> 3689 /// <remarks> 3690 /// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the 3691 /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the 3692 /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have 3693 /// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations. 3694 /// </remarks> 3695 /**/ 3696 bool set(_ResultType _Result) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 3697 { 3698 // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored. 3699 if (_IsTriggered()) 3700 { 3701 return false; 3702 } 3703 3704 _TaskList _Tasks; 3705 bool _RunContinuations = false; 3706 { 3707 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec); 3708 3709 if (!_IsTriggered()) 3710 { 3711 #if _MSC_VER >= 1800 3712 _M_Impl->_M_value.Set(_Result); 3713 #else 3714 _M_Impl->_M_value = _Result; 3715 #endif 3716 _M_Impl->_M_fHasValue = true; 3717 3718 _Tasks.swap(_M_Impl->_M_tasks); 3719 _RunContinuations = true; 3720 } 3721 } 3722 3723 if (_RunContinuations) 3724 { 3725 for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt) 3726 { 3727 #if _MSC_VER >= 1800 3728 // If current task was cancelled by a cancellation_token, it would be in cancel pending state. 3729 if ((*_TaskIt)->_IsPendingCancel()) 3730 (*_TaskIt)->_Cancel(true); 3731 else 3732 { 3733 // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all 3734 // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we 3735 // need to run continuations after the lock is released. 3736 (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get()); 3737 } 3738 #else 3739 // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all 3740 // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we 3741 // need to run continuations after the lock is released. 3742 (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value); 3743 #endif 3744 } 3745 if (_M_Impl->_HasUserException()) 3746 { 3747 _M_Impl->_M_exceptionHolder.reset(); 3748 } 3749 return true; 3750 } 3751 3752 return false; 3753 } 3754 #if _MSC_VER >= 1800 3755 3756 template<typename _E> 3757 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 3758 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 3759 { 3760 // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception. 3761 return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK()); 3762 } 3763 #endif 3764 3765 /// <summary> 3766 /// Propagates an exception to all tasks associated with this event. 3767 /// </summary> 3768 /// <param> 3769 /// The exception_ptr that indicates the exception to set this event with. 3770 /// </param> 3771 /**/ 3772 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 3773 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 3774 { 3775 // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception. 3776 #if _MSC_VER >= 1800 3777 return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK()); 3778 #else 3779 return _Cancel(_ExceptionPtr, _ReturnAddress()); 3780 #endif 3781 } 3782 3783 /// <summary> 3784 /// Internal method to cancel the task_completion_event. Any task created using this event will be marked as canceled if it has 3785 /// not already been set. 3786 /// </summary> 3787 bool _Cancel() const 3788 { 3789 // Cancel with the stored exception if one exists. 3790 return _CancelInternal(); 3791 } 3792 3793 /// <summary> 3794 /// Internal method to cancel the task_completion_event with the exception provided. Any task created using this event will be canceled 3795 /// with the same exception. 3796 /// </summary> 3797 template<typename _ExHolderType> 3798 #if _MSC_VER >= 1800 3799 bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack()) const 3800 #else 3801 bool _Cancel(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const 3802 #endif 3803 { 3804 (void)_SetExceptionAddressHint; 3805 bool _Canceled; 3806 #if _MSC_VER >= 1800 3807 if(_StoreException(_ExHolder, _SetExceptionAddressHint)) 3808 #else 3809 if (_StoreException(_ExHolder)) 3810 #endif 3811 { 3812 _Canceled = _CancelInternal(); 3813 _CONCRT_ASSERT(_Canceled); 3814 } 3815 else 3816 { 3817 _Canceled = false; 3818 } 3819 return _Canceled; 3820 } 3821 3822 /// <summary> 3823 /// Internal method that stores an exception in the task completion event. This is used internally by when_any. 3824 /// Note, this does not cancel the task completion event. A task completion event with a stored exception 3825 /// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present. 3826 /// </summary> 3827 template<typename _ExHolderType> 3828 #if _MSC_VER >= 1800 3829 bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint = details::_TaskCreationCallstack()) const 3830 #else 3831 bool _StoreException(_ExHolderType _ExHolder, void* _SetExceptionAddressHint = nullptr) const 3832 #endif 3833 { 3834 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec); 3835 if (!_IsTriggered() && !_M_Impl->_HasUserException()) 3836 { 3837 // Create the exception holder only if we have ensured there we will be successful in setting it onto the 3838 // task completion event. Failing to do so will result in an unobserved task exception. 3839 _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint); 3840 return true; 3841 } 3842 return false; 3843 } 3844 3845 /// <summary> 3846 /// Tests whether current event has been either Set, or Canceled. 3847 /// </summary> 3848 bool _IsTriggered() const 3849 { 3850 return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled; 3851 } 3852 3853 private: 3854 3855 #if _MSC_VER >= 1800 3856 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, const details::_TaskCreationCallstack&) 3857 #else 3858 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder, void*) 3859 #endif 3860 { 3861 return _ExHolder; 3862 } 3863 3864 #if _MSC_VER >= 1800 3865 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint) 3866 #else 3867 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, void* _SetExceptionAddressHint) 3868 #endif 3869 { 3870 return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint); 3871 } 3872 3873 template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask 3874 template <typename T> friend class task_completion_event; 3875 3876 typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList; 3877 3878 /// <summary> 3879 /// Cancels the task_completion_event. 3880 /// </summary> 3881 bool _CancelInternal() const 3882 { 3883 // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal 3884 // will never be invoked if the task completion event has been set. 3885 _CONCRT_ASSERT(!_M_Impl->_M_fHasValue); 3886 if (_M_Impl->_M_fIsCanceled) 3887 { 3888 return false; 3889 } 3890 3891 _TaskList _Tasks; 3892 bool _Cancel = false; 3893 { 3894 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec); 3895 _CONCRT_ASSERT(!_M_Impl->_M_fHasValue); 3896 if (!_M_Impl->_M_fIsCanceled) 3897 { 3898 _M_Impl->_M_fIsCanceled = true; 3899 _Tasks.swap(_M_Impl->_M_tasks); 3900 _Cancel = true; 3901 } 3902 } 3903 3904 bool _UserException = _M_Impl->_HasUserException(); 3905 3906 if (_Cancel) 3907 { 3908 for (auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt) 3909 { 3910 // Need to call this after the lock is released. See comments in set(). 3911 if (_UserException) 3912 { 3913 (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true); 3914 } 3915 else 3916 { 3917 (*_TaskIt)->_Cancel(true); 3918 } 3919 } 3920 } 3921 return _Cancel; 3922 } 3923 3924 /// <summary> 3925 /// Register a task with this event. This function is called when a task is constructed using 3926 /// a task_completion_event. 3927 /// </summary> 3928 void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam) 3929 { 3930 details::scoped_lock _LockHolder(_M_Impl->_M_taskListCritSec); 3931 #if _MSC_VER < 1800 3932 _TaskParam->_SetScheduledEvent(); 3933 #endif 3934 //If an exception was already set on this event, then cancel the task with the stored exception. 3935 if (_M_Impl->_HasUserException()) 3936 { 3937 _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true); 3938 } 3939 else if (_M_Impl->_M_fHasValue) 3940 { 3941 #if _MSC_VER >= 1800 3942 _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get()); 3943 #else 3944 _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value); 3945 #endif 3946 } 3947 else 3948 { 3949 _M_Impl->_M_tasks.push_back(_TaskParam); 3950 } 3951 } 3952 3953 std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl; 3954 }; 3955 3956 /// <summary> 3957 /// The <c>task_completion_event</c> class allows you to delay the execution of a task until a condition is satisfied, 3958 /// or start a task in response to an external event. 3959 /// </summary> 3960 /// <remarks> 3961 /// Use a task created from a task completion event when your scenario requires you to create a task that will complete, and 3962 /// thereby have its continuations scheduled for execution, at some point in the future. The <c>task_completion_event</c> must 3963 /// have the same type as the task you create, and calling the set method on the task completion event with a value of that type 3964 /// will cause the associated task to complete, and provide that value as a result to its continuations. 3965 /// <para>If the task completion event is never signaled, any tasks created from it will be canceled when it is destructed.</para> 3966 /// <para><c>task_completion_event</c> behaves like a smart pointer, and should be passed by value.</para> 3967 /// </remarks> 3968 /// <seealso cref="task Class"/> 3969 /**/ 3970 template<> 3971 class task_completion_event<void> 3972 { 3973 public: 3974 /// <summary> 3975 /// Sets the task completion event. 3976 /// </summary> 3977 /// <returns> 3978 /// The method returns <c>true</c> if it was successful in setting the event. It returns <c>false</c> if the event is already set. 3979 /// </returns> 3980 /// <remarks> 3981 /// In the presence of multiple or concurrent calls to <c>set</c>, only the first call will succeed and its result (if any) will be stored in the 3982 /// task completion event. The remaining sets are ignored and the method will return false. When you set a task completion event, all the 3983 /// tasks created from that event will immediately complete, and its continuations, if any, will be scheduled. Task completion objects that have 3984 /// a <typeparamref name="_ResultType"/> other than <c>void</c> will pass the value <paramref value="_Result"/> to their continuations. 3985 /// </remarks> 3986 /**/ 3987 bool set() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 3988 { 3989 return _M_unitEvent.set(details::_Unit_type()); 3990 } 3991 #if _MSC_VER >= 1800 3992 3993 template<typename _E> 3994 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 3995 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 3996 { 3997 return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK()); 3998 } 3999 #endif 4000 4001 /// <summary> 4002 /// Propagates an exception to all tasks associated with this event. 4003 /// </summary> 4004 /// <param> 4005 /// The exception_ptr that indicates the exception to set this event with. 4006 /// </param> 4007 /**/ 4008 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4009 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 4010 { 4011 // It is important that _ReturnAddress() evaluate to the instruction after the call instruction for set_exception. 4012 #if _MSC_VER >= 1800 4013 return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK()); 4014 #else 4015 return _M_unitEvent._Cancel(_ExceptionPtr, _ReturnAddress()); 4016 #endif 4017 } 4018 4019 /// <summary> 4020 /// Cancel the task_completion_event. Any task created using this event will be marked as canceled if it has 4021 /// not already been set. 4022 /// </summary> 4023 void _Cancel() const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas 4024 { 4025 _M_unitEvent._Cancel(); 4026 } 4027 4028 /// <summary> 4029 /// Cancel the task_completion_event with the exception holder provided. Any task created using this event will be canceled 4030 /// with the same exception. 4031 /// </summary> 4032 void _Cancel(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const 4033 { 4034 _M_unitEvent._Cancel(_ExHolder); 4035 } 4036 4037 /// <summary> 4038 /// Method that stores an exception in the task completion event. This is used internally by when_any. 4039 /// Note, this does not cancel the task completion event. A task completion event with a stored exception 4040 /// can bet set() successfully. If it is canceled, it will cancel with the stored exception, if one is present. 4041 /// </summary> 4042 bool _StoreException(const std::shared_ptr<details::_ExceptionHolder>& _ExHolder) const 4043 { 4044 return _M_unitEvent._StoreException(_ExHolder); 4045 } 4046 4047 /// <summary> 4048 /// Test whether current event has been either Set, or Canceled. 4049 /// </summary> 4050 bool _IsTriggered() const 4051 { 4052 return _M_unitEvent._IsTriggered(); 4053 } 4054 4055 private: 4056 template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask 4057 4058 /// <summary> 4059 /// Register a task with this event. This function is called when a task is constructed using 4060 /// a task_completion_event. 4061 /// </summary> 4062 void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam) 4063 { 4064 _M_unitEvent._RegisterTask(_TaskParam); 4065 } 4066 4067 // The void event contains an event a dummy type so common code can be used for events with void and non-void results. 4068 task_completion_event<details::_Unit_type> _M_unitEvent; 4069 }; 4070 namespace details 4071 { 4072 // 4073 // Compile-time validation helpers 4074 // 4075 4076 // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here. 4077 // 4078 // Anything callable is fine 4079 template<typename _ReturnType, typename _Ty> 4080 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, int, int) -> typename decltype(_Param(), std::true_type()); 4081 4082 // Anything callable with a task return value is fine 4083 template<typename _ReturnType, typename _Ty> 4084 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<task<_ReturnType>*>()), std::true_type()); 4085 4086 // Anything callable with a return value is fine 4087 template<typename _ReturnType, typename _Ty> 4088 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<_ReturnType*>()), std::true_type()); 4089 4090 // Anything that has GetResults is fine: this covers AsyncAction* 4091 template<typename _ReturnType, typename _Ty> 4092 auto _IsValidTaskCtor(_Ty _Param, int, int, int, int, ...) -> typename decltype(_Param->GetResults(), std::true_type()); 4093 4094 // Anything that has GetResults(TResult_abi*) is fine: this covers AsyncOperation* 4095 template<typename _ReturnType, typename _Ty> 4096 auto _IsValidTaskCtor(_Ty _Param, int, int, int, ...) -> typename decltype(_Param->GetResults(stdx::declval<decltype(_GetUnwrappedType(stdx::declval<_Ty>()))*>()), std::true_type()); 4097 4098 // Allow parameters with set: this covers task_completion_event 4099 template<typename _ReturnType, typename _Ty> 4100 auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> typename decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type()); 4101 4102 template<typename _ReturnType, typename _Ty> 4103 auto _IsValidTaskCtor(_Ty _Param, int, ...) -> typename decltype(_Param.set(), std::true_type()); 4104 4105 // All else is invalid 4106 template<typename _ReturnType, typename _Ty> 4107 std::false_type _IsValidTaskCtor(_Ty _Param, ...); 4108 4109 template<typename _ReturnType, typename _Ty> 4110 void _ValidateTaskConstructorArgs(_Ty _Param) 4111 { 4112 (void)_Param; 4113 static_assert(std::is_same<decltype(details::_IsValidTaskCtor<_ReturnType>(_Param, 0, 0, 0, 0, 0, 0, 0)), std::true_type>::value, 4114 "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event" 4115 ); 4116 static_assert(!(std::is_same<_Ty, _ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value), 4117 "incorrect template argument for task; consider using the return type of the async operation"); 4118 } 4119 // Helpers for create_async validation 4120 // 4121 // A parameter lambda taking no arguments is valid 4122 template<typename _ReturnType, typename _Ty> 4123 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, int, int) -> typename decltype(_Param(), std::true_type()); 4124 4125 // A parameter lambda taking a result argument is valid 4126 template<typename _ReturnType, typename _Ty> 4127 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, int, ...) -> typename decltype(_Param(stdx::declval<_ReturnType*>()), std::true_type()); 4128 4129 // A parameter lambda taking an cancellation_token argument is valid 4130 template<typename _ReturnType, typename _Ty> 4131 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, int, ...) -> typename decltype(_Param(Concurrency::cancellation_token::none()), std::true_type()); 4132 4133 // A parameter lambda taking an cancellation_token argument and a result argument is valid 4134 template<typename _ReturnType, typename _Ty> 4135 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, int, ...) -> typename decltype(_Param(Concurrency::cancellation_token::none(), stdx::declval<_ReturnType*>()), std::true_type()); 4136 4137 // A parameter lambda taking a progress report argument is valid 4138 template<typename _ReturnType, typename _Ty> 4139 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type()); 4140 4141 // A parameter lambda taking a progress report argument and a result argument is valid 4142 template<typename _ReturnType, typename _Ty> 4143 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), stdx::declval<_ReturnType*>()), std::true_type()); 4144 4145 // A parameter lambda taking a progress report and a cancellation_token argument is valid 4146 template<typename _ReturnType, typename _Ty> 4147 static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), Concurrency::cancellation_token::none()), std::true_type()); 4148 4149 // A parameter lambda taking a progress report and a cancellation_token argument and a result argument is valid 4150 template<typename _ReturnType, typename _Ty> 4151 static auto _IsValidCreateAsync(_Ty _Param, int, ...) -> typename decltype(_Param(details::_ProgressReporterCtorArgType(), Concurrency::cancellation_token::none(), stdx::declval<_ReturnType*>()), std::true_type()); 4152 4153 // All else is invalid 4154 template<typename _ReturnType, typename _Ty> 4155 static std::false_type _IsValidCreateAsync(_Ty _Param, ...); 4156 } 4157 4158 /// <summary> 4159 /// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously, 4160 /// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces 4161 /// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result. 4162 /// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using 4163 /// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns. 4164 /// </summary> 4165 /// <typeparam name="_ReturnType"> 4166 /// The result type of this task. 4167 /// </typeparam> 4168 /// <remarks> 4169 /// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>. 4170 /// </remarks> 4171 /**/ 4172 template<typename _ReturnType> 4173 class task 4174 { 4175 public: 4176 /// <summary> 4177 /// The type of the result an object of this class produces. 4178 /// </summary> 4179 /**/ 4180 typedef _ReturnType result_type; 4181 4182 /// <summary> 4183 /// Constructs a <c>task</c> object. 4184 /// </summary> 4185 /// <remarks> 4186 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 4187 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 4188 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 4189 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 4190 /// completion event is set.</para> 4191 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 4192 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 4193 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 4194 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 4195 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 4196 /// and not when the lamda returns.</para> 4197 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 4198 /// without the need for locks.</para> 4199 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 4200 /// to Windows Store apps.</para> 4201 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4202 /// </remarks> 4203 /**/ 4204 task() : _M_Impl(nullptr) 4205 { 4206 // The default constructor should create a task with a nullptr impl. This is a signal that the 4207 // task is not usable and should throw if any wait(), get() or then() APIs are used. 4208 } 4209 4210 /// <summary> 4211 /// Constructs a <c>task</c> object. 4212 /// </summary> 4213 /// <typeparam name="_Ty"> 4214 /// The type of the parameter from which the task is to be constructed. 4215 /// </typeparam> 4216 /// <param name="_Param"> 4217 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c> 4218 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function 4219 /// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>, 4220 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. 4221 /// </param> 4222 /// <param name="_Token"> 4223 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives 4224 /// the token <c>cancellation_token::none()</c>. 4225 /// </param> 4226 /// <remarks> 4227 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 4228 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 4229 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 4230 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 4231 /// completion event is set.</para> 4232 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 4233 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 4234 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 4235 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 4236 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 4237 /// and not when the lamda returns.</para> 4238 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 4239 /// without the need for locks.</para> 4240 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 4241 /// to Windows Store apps.</para> 4242 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4243 /// </remarks> 4244 /**/ 4245 template<typename _Ty> 4246 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4247 explicit task(_Ty _Param) 4248 { 4249 #if _MSC_VER >= 1800 4250 task_options _TaskOptions; 4251 #endif 4252 details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param); 4253 4254 #if _MSC_VER >= 1800 4255 _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); 4256 #else 4257 _CreateImpl(Concurrency::cancellation_token::none()._GetImplValue()); 4258 #endif 4259 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor. 4260 #if _MSC_VER >= 1800 4261 _SetTaskCreationCallstack(_CAPTURE_CALLSTACK()); 4262 #else 4263 _SetTaskCreationAddressHint(_ReturnAddress()); 4264 #endif 4265 _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0)); 4266 } 4267 4268 /// <summary> 4269 /// Constructs a <c>task</c> object. 4270 /// </summary> 4271 /// <typeparam name="_Ty"> 4272 /// The type of the parameter from which the task is to be constructed. 4273 /// </typeparam> 4274 /// <param name="_Param"> 4275 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c> 4276 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function 4277 /// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>, 4278 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. 4279 /// </param> 4280 /// <param name="_Token"> 4281 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives 4282 /// the token <c>cancellation_token::none()</c>. 4283 /// </param> 4284 /// <remarks> 4285 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 4286 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 4287 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 4288 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 4289 /// completion event is set.</para> 4290 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 4291 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 4292 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 4293 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 4294 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 4295 /// and not when the lamda returns.</para> 4296 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 4297 /// without the need for locks.</para> 4298 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 4299 /// to Windows Store apps.</para> 4300 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4301 /// </remarks> 4302 /**/ 4303 template<typename _Ty> 4304 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4305 #if _MSC_VER >= 1800 4306 explicit task(_Ty _Param, const task_options &_TaskOptions) 4307 #else 4308 explicit task(_Ty _Param, Concurrency::cancellation_token _Token) 4309 #endif 4310 { 4311 details::_ValidateTaskConstructorArgs<_ReturnType, _Ty>(_Param); 4312 4313 #if _MSC_VER >= 1800 4314 _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); 4315 #else 4316 _CreateImpl(_Token._GetImplValue()); 4317 #endif 4318 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor. 4319 #if _MSC_VER >= 1800 4320 _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK()); 4321 #else 4322 _SetTaskCreationAddressHint(_ReturnAddress()); 4323 #endif 4324 _TaskInitMaybeFunctor(_Param, details::_IsCallable<_ReturnType>(_Param, 0, 0, 0)); 4325 } 4326 4327 /// <summary> 4328 /// Constructs a <c>task</c> object. 4329 /// </summary> 4330 /// <param name="_Other"> 4331 /// The source <c>task</c> object. 4332 /// </param> 4333 /// <remarks> 4334 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 4335 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 4336 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 4337 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 4338 /// completion event is set.</para> 4339 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 4340 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 4341 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 4342 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 4343 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 4344 /// and not when the lamda returns.</para> 4345 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 4346 /// without the need for locks.</para> 4347 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 4348 /// to Windows Store apps.</para> 4349 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4350 /// </remarks> 4351 /**/ 4352 task(const task& _Other) : _M_Impl(_Other._M_Impl) {} 4353 4354 /// <summary> 4355 /// Constructs a <c>task</c> object. 4356 /// </summary> 4357 /// <param name="_Other"> 4358 /// The source <c>task</c> object. 4359 /// </param> 4360 /// <remarks> 4361 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 4362 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 4363 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 4364 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 4365 /// completion event is set.</para> 4366 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 4367 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 4368 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 4369 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 4370 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 4371 /// and not when the lamda returns.</para> 4372 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 4373 /// without the need for locks.</para> 4374 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 4375 /// to Windows Store apps.</para> 4376 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4377 /// </remarks> 4378 /**/ 4379 task(task&& _Other) : _M_Impl(std::move(_Other._M_Impl)) {} 4380 4381 /// <summary> 4382 /// Replaces the contents of one <c>task</c> object with another. 4383 /// </summary> 4384 /// <param name="_Other"> 4385 /// The source <c>task</c> object. 4386 /// </param> 4387 /// <remarks> 4388 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same 4389 /// actual task as <paramref name="_Other"/> does. 4390 /// </remarks> 4391 /**/ 4392 task& operator=(const task& _Other) 4393 { 4394 if (this != &_Other) 4395 { 4396 _M_Impl = _Other._M_Impl; 4397 } 4398 return *this; 4399 } 4400 4401 /// <summary> 4402 /// Replaces the contents of one <c>task</c> object with another. 4403 /// </summary> 4404 /// <param name="_Other"> 4405 /// The source <c>task</c> object. 4406 /// </param> 4407 /// <remarks> 4408 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same 4409 /// actual task as <paramref name="_Other"/> does. 4410 /// </remarks> 4411 /**/ 4412 task& operator=(task&& _Other) 4413 { 4414 if (this != &_Other) 4415 { 4416 _M_Impl = std::move(_Other._M_Impl); 4417 } 4418 return *this; 4419 } 4420 4421 /// <summary> 4422 /// Adds a continuation task to this task. 4423 /// </summary> 4424 /// <typeparam name="_Function"> 4425 /// The type of the function object that will be invoked by this task. 4426 /// </typeparam> 4427 /// <param name="_Func"> 4428 /// The continuation function to execute when this task completes. This continuation function must take as input 4429 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 4430 /// of the result this task produces. 4431 /// </param> 4432 /// <returns> 4433 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 4434 /// </returns> 4435 /// <remarks> 4436 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 4437 /// to Windows Store apps. 4438 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4439 /// </remarks> 4440 /**/ 4441 template<typename _Function> 4442 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4443 auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4444 { 4445 #if _MSC_VER >= 1800 4446 task_options _TaskOptions; 4447 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 4448 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions); 4449 #else 4450 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, task_continuation_context::use_default()); 4451 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 4452 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 4453 return _ContinuationTask; 4454 #endif 4455 } 4456 4457 /// <summary> 4458 /// Adds a continuation task to this task. 4459 /// </summary> 4460 /// <typeparam name="_Function"> 4461 /// The type of the function object that will be invoked by this task. 4462 /// </typeparam> 4463 /// <param name="_Func"> 4464 /// The continuation function to execute when this task completes. This continuation function must take as input 4465 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 4466 /// of the result this task produces. 4467 /// </param> 4468 /// <param name="_CancellationToken"> 4469 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit 4470 /// the token of its antecedent task. 4471 /// </param> 4472 /// <returns> 4473 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 4474 /// </returns> 4475 /// <remarks> 4476 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 4477 /// to Windows Store apps. 4478 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4479 /// </remarks> 4480 /**/ 4481 template<typename _Function> 4482 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4483 #if _MSC_VER >= 1800 4484 auto then(const _Function& _Func, task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4485 #else 4486 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4487 #endif 4488 { 4489 #if _MSC_VER >= 1800 4490 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 4491 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions); 4492 #else 4493 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default()); 4494 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 4495 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 4496 return _ContinuationTask; 4497 #endif 4498 } 4499 #if _MSC_VER < 1800 4500 /// <summary> 4501 /// Adds a continuation task to this task. 4502 /// </summary> 4503 /// <typeparam name="_Function"> 4504 /// The type of the function object that will be invoked by this task. 4505 /// </typeparam> 4506 /// <param name="_Func"> 4507 /// The continuation function to execute when this task completes. This continuation function must take as input 4508 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 4509 /// of the result this task produces. 4510 /// </param> 4511 /// <param name="_ContinuationContext"> 4512 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a 4513 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see> 4514 /// </param> 4515 /// <returns> 4516 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 4517 /// </returns> 4518 /// <remarks> 4519 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 4520 /// to Windows Store apps. 4521 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4522 /// </remarks> 4523 /**/ 4524 template<typename _Function> 4525 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4526 auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4527 { 4528 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, nullptr, _ContinuationContext); 4529 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 4530 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 4531 return _ContinuationTask; 4532 } 4533 #endif 4534 /// <summary> 4535 /// Adds a continuation task to this task. 4536 /// </summary> 4537 /// <typeparam name="_Function"> 4538 /// The type of the function object that will be invoked by this task. 4539 /// </typeparam> 4540 /// <param name="_Func"> 4541 /// The continuation function to execute when this task completes. This continuation function must take as input 4542 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 4543 /// of the result this task produces. 4544 /// </param> 4545 /// <param name="_CancellationToken"> 4546 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit 4547 /// the token of its antecedent task. 4548 /// </param> 4549 /// <param name="_ContinuationContext"> 4550 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a 4551 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see> 4552 /// </param> 4553 /// <returns> 4554 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 4555 /// </returns> 4556 /// <remarks> 4557 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 4558 /// to Windows Store apps. 4559 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 4560 /// </remarks> 4561 /**/ 4562 template<typename _Function> 4563 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 4564 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4565 { 4566 #if _MSC_VER >= 1800 4567 task_options _TaskOptions(_CancellationToken, _ContinuationContext); 4568 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 4569 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions); 4570 #else 4571 auto _ContinuationTask = _ThenImpl<_ReturnType, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext); 4572 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 4573 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 4574 return _ContinuationTask; 4575 #endif 4576 } 4577 4578 /// <summary> 4579 /// Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks 4580 /// dependencies are satisfied, and it has not already been picked up for execution by a background worker. 4581 /// </summary> 4582 /// <returns> 4583 /// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception 4584 /// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception. 4585 /// </returns> 4586 /**/ 4587 task_status wait() const 4588 { 4589 if (_M_Impl == nullptr) 4590 { 4591 throw Concurrency::invalid_operation("wait() cannot be called on a default constructed task."); 4592 } 4593 4594 return _M_Impl->_Wait(); 4595 } 4596 4597 /// <summary> 4598 /// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to 4599 /// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>. 4600 /// </summary> 4601 /// <returns> 4602 /// The result of the task. 4603 /// </returns> 4604 /// <remarks> 4605 /// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task 4606 /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception. 4607 /// </remarks> 4608 /**/ 4609 _ReturnType get() const 4610 { 4611 if (_M_Impl == nullptr) 4612 { 4613 throw Concurrency::invalid_operation("get() cannot be called on a default constructed task."); 4614 } 4615 4616 if (_M_Impl->_Wait() == Concurrency::canceled) 4617 { 4618 throw Concurrency::task_canceled(); 4619 } 4620 4621 return _M_Impl->_GetResult(); 4622 } 4623 #if _MSC_VER >= 1800 4624 /// <summary> 4625 /// Determines if the task is completed. 4626 /// </summary> 4627 /// <returns> 4628 /// True if the task has completed, false otherwise. 4629 /// </returns> 4630 /// <remarks> 4631 /// The function returns true if the task is completed or canceled (with or without user exception). 4632 /// </remarks> 4633 bool is_done() const 4634 { 4635 if (!_M_Impl) 4636 { 4637 throw Concurrency::invalid_operation("is_done() cannot be called on a default constructed task."); 4638 } 4639 4640 return _M_Impl->_IsDone(); 4641 } 4642 4643 /// <summary> 4644 /// Returns the scheduler for this task 4645 /// </summary> 4646 /// <returns> 4647 /// A pointer to the scheduler 4648 /// </returns> 4649 Concurrency::scheduler_ptr scheduler() const 4650 { 4651 if (!_M_Impl) 4652 { 4653 throw Concurrency::invalid_operation("scheduler() cannot be called on a default constructed task."); 4654 } 4655 4656 return _M_Impl->_GetScheduler(); 4657 } 4658 #endif 4659 /// <summary> 4660 /// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task. 4661 /// </summary> 4662 /// <returns> 4663 /// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise. 4664 /// </returns> 4665 /**/ 4666 bool is_apartment_aware() const 4667 { 4668 if (_M_Impl == nullptr) 4669 { 4670 throw Concurrency::invalid_operation("is_apartment_aware() cannot be called on a default constructed task."); 4671 } 4672 return _M_Impl->_IsApartmentAware(); 4673 } 4674 4675 /// <summary> 4676 /// Determines whether two <c>task</c> objects represent the same internal task. 4677 /// </summary> 4678 /// <returns> 4679 /// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise. 4680 /// </returns> 4681 /**/ 4682 bool operator==(const task<_ReturnType>& _Rhs) const 4683 { 4684 return (_M_Impl == _Rhs._M_Impl); 4685 } 4686 4687 /// <summary> 4688 /// Determines whether two <c>task</c> objects represent different internal tasks. 4689 /// </summary> 4690 /// <returns> 4691 /// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise. 4692 /// </returns> 4693 /**/ 4694 bool operator!=(const task<_ReturnType>& _Rhs) const 4695 { 4696 return !operator==(_Rhs); 4697 } 4698 4699 /// <summary> 4700 /// Create an underlying task implementation. 4701 /// </summary> 4702 #if _MSC_VER >= 1800 4703 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler) 4704 #else 4705 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct) 4706 #endif 4707 { 4708 _CONCRT_ASSERT(_Ct != nullptr); 4709 #if _MSC_VER >= 1800 4710 _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct, _Scheduler); 4711 #else 4712 _M_Impl = details::_Task_ptr<_ReturnType>::_Make(_Ct); 4713 #endif 4714 if (_Ct != Concurrency::details::_CancellationTokenState::_None()) 4715 { 4716 #if _MSC_VER >= 1800 4717 _M_Impl->_RegisterCancellation(_M_Impl); 4718 #else 4719 _M_Impl->_RegisterCancellation(); 4720 #endif 4721 } 4722 } 4723 4724 /// <summary> 4725 /// Return the underlying implementation for this task. 4726 /// </summary> 4727 const typename details::_Task_ptr<_ReturnType>::_Type & _GetImpl() const 4728 { 4729 return _M_Impl; 4730 } 4731 4732 /// <summary> 4733 /// Set the implementation of the task to be the supplied implementaion. 4734 /// </summary> 4735 void _SetImpl(const typename details::_Task_ptr<_ReturnType>::_Type & _Impl) 4736 { 4737 _CONCRT_ASSERT(_M_Impl == nullptr); 4738 _M_Impl = _Impl; 4739 } 4740 4741 /// <summary> 4742 /// Set the implementation of the task to be the supplied implementaion using a move instead of a copy. 4743 /// </summary> 4744 void _SetImpl(typename details::_Task_ptr<_ReturnType>::_Type && _Impl) 4745 { 4746 _CONCRT_ASSERT(_M_Impl == nullptr); 4747 _M_Impl = std::move(_Impl); 4748 } 4749 4750 /// <summary> 4751 /// Sets a property determining whether the task is apartment aware. 4752 /// </summary> 4753 void _SetAsync(bool _Async = true) 4754 { 4755 _GetImpl()->_SetAsync(_Async); 4756 } 4757 4758 /// <summary> 4759 /// Sets a field in the task impl to the return address for calls to the task constructors and the then method. 4760 /// </summary> 4761 #if _MSC_VER >= 1800 4762 void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack) 4763 { 4764 _GetImpl()->_SetTaskCreationCallstack(_callstack); 4765 } 4766 #else 4767 void _SetTaskCreationAddressHint(void* _Address) 4768 { 4769 _GetImpl()->_SetTaskCreationAddressHint(_Address); 4770 } 4771 #endif 4772 /// <summary> 4773 /// An internal version of then that takes additional flags and always execute the continuation inline by default. 4774 /// When _ForceInline is set to false, continuations inlining will be limited to default _DefaultAutoInline. 4775 /// This function is Used for runtime internal continuations only. 4776 /// </summary> 4777 template<typename _Function> 4778 #if _MSC_VER >= 1800 4779 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, 4780 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4781 { 4782 // inherit from antecedent 4783 auto _Scheduler = _GetImpl()->_GetScheduler(); 4784 4785 return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode); 4786 } 4787 #else 4788 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, bool _Aggregating, 4789 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType 4790 { 4791 return _ThenImpl<_ReturnType, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode); 4792 } 4793 #endif 4794 4795 private: 4796 template <typename T> friend class task; 4797 4798 // A helper class template that transforms an intial task lambda returns void into a lambda that returns a non-void type (details::_Unit_type is used 4799 // to substitute for void). This is to minimize the special handling required for 'void'. 4800 template<typename _RetType> 4801 class _Init_func_transformer 4802 { 4803 public: 4804 static auto _Perform(std::function<HRESULT(_RetType*)> _Func) -> decltype(_Func) 4805 { 4806 return _Func; 4807 } 4808 }; 4809 4810 template<> 4811 class _Init_func_transformer<void> 4812 { 4813 public: 4814 static auto _Perform(std::function<HRESULT(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func)) 4815 { 4816 return details::_MakeVoidToUnitFunc(_Func); 4817 } 4818 }; 4819 4820 // The task handle type used to construct an 'initial task' - a task with no dependents. 4821 template <typename _InternalReturnType, typename _Function, typename _TypeSelection> 4822 struct _InitialTaskHandle : 4823 details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore> 4824 { 4825 _Function _M_function; 4826 _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _Function) : _M_function(_Function), _PPLTaskHandle(_TaskImpl) 4827 { 4828 } 4829 virtual ~_InitialTaskHandle() {} 4830 4831 #if _MSC_VER >= 1800 4832 template <typename _Func, typename _RetArg> 4833 auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _RetArg && _retArg) const -> decltype(_func(std::forward<_RetArg>(_retArg))) 4834 { 4835 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger); 4836 return _func(std::forward<_RetArg>(_retArg)); 4837 } 4838 #endif 4839 4840 void _Perform() const 4841 { 4842 _Init(_TypeSelection()); 4843 } 4844 #if _MSC_VER >= 1800 4845 4846 void _SyncCancelAndPropagateException() const 4847 { 4848 this->_M_pTask->_Cancel(true); 4849 } 4850 #endif 4851 // 4852 // Overload 0: returns _InternalReturnType 4853 // 4854 // This is the most basic task with no unwrapping 4855 // 4856 void _Init(details::_TypeSelectorNoAsync) const 4857 { 4858 _ReturnType retVal; 4859 #if _MSC_VER >= 1800 4860 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function), &retVal); 4861 #else 4862 HRESULT hr = _Init_func_transformer<_InternalReturnType>::_Perform(_M_function)(&retVal); 4863 #endif 4864 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4865 _M_pTask->_FinalizeAndRunContinuations(retVal); 4866 } 4867 4868 // 4869 // Overload 1: returns IAsyncOperation<_InternalReturnType>* 4870 // or 4871 // returns task<_InternalReturnType> 4872 // 4873 // This is task whose functor returns an async operation or a task which will be unwrapped for continuation 4874 // Depending on the output type, the right _AsyncInit gets invoked 4875 // 4876 void _Init(details::_TypeSelectorAsyncTask) const 4877 { 4878 task<_InternalReturnType> retVal; 4879 #if _MSC_VER >= 1800 4880 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal); 4881 #else 4882 HRESULT hr = _M_function(&retVal); 4883 #endif 4884 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4885 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, retVal); 4886 } 4887 void _Init(details::_TypeSelectorAsyncOperation) const 4888 { 4889 _ReturnType retVal; 4890 #if _MSC_VER >= 1800 4891 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal); 4892 #else 4893 HRESULT hr = _M_function(&retVal); 4894 #endif 4895 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4896 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, 4897 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_InternalReturnType>>(retVal).Get()); 4898 } 4899 4900 // 4901 // Overload 2: returns IAsyncAction* 4902 // 4903 // This is task whose functor returns an async action which will be unwrapped for continuation 4904 // 4905 void _Init(details::_TypeSelectorAsyncAction) const 4906 { 4907 _ReturnType retVal; 4908 #if _MSC_VER >= 1800 4909 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal); 4910 #else 4911 HRESULT hr = _M_function(&retVal); 4912 #endif 4913 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4914 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(retVal).Get()); 4915 } 4916 4917 // 4918 // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>* 4919 // 4920 // This is task whose functor returns an async operation with progress which will be unwrapped for continuation 4921 // 4922 void _Init(details::_TypeSelectorAsyncOperationWithProgress) const 4923 { 4924 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType; 4925 _ReturnType retVal; 4926 #if _MSC_VER >= 1800 4927 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal); 4928 #else 4929 HRESULT hr = _M_function(&retVal); 4930 #endif 4931 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4932 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, 4933 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType, _ProgressType>>(retVal).Get()); 4934 } 4935 4936 // 4937 // Overload 4: returns IAsyncActionWithProgress<_ProgressType>* 4938 // 4939 // This is task whose functor returns an async action with progress which will be unwrapped for continuation 4940 // 4941 void _Init(details::_TypeSelectorAsyncActionWithProgress) const 4942 { 4943 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType; 4944 _ReturnType retVal; 4945 #if _MSC_VER >= 1800 4946 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, &retVal); 4947 #else 4948 HRESULT hr = _M_function(&retVal); 4949 #endif 4950 if (FAILED(hr)) throw std::make_exception_ptr(hr); 4951 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(_M_pTask, 4952 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal).Get()); 4953 } 4954 }; 4955 4956 /// <summary> 4957 /// A helper class template that transforms a continuation lambda that either takes or returns void, or both, into a lambda that takes and returns a 4958 /// non-void type (details::_Unit_type is used to substitute for void). This is to minimize the special handling required for 'void'. 4959 /// </summary> 4960 template<typename _InpType, typename _OutType> 4961 class _Continuation_func_transformer 4962 { 4963 public: 4964 static auto _Perform(std::function<HRESULT(_InpType, _OutType*)> _Func) -> decltype(_Func) 4965 { 4966 return _Func; 4967 } 4968 }; 4969 4970 template<typename _OutType> 4971 class _Continuation_func_transformer<void, _OutType> 4972 { 4973 public: 4974 static auto _Perform(std::function<HRESULT(_OutType*)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func)) 4975 { 4976 return details::_MakeUnitToTFunc<_OutType>(_Func); 4977 } 4978 }; 4979 4980 template<typename _InType> 4981 class _Continuation_func_transformer<_InType, void> 4982 { 4983 public: 4984 static auto _Perform(std::function<HRESULT(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func)) 4985 { 4986 return details::_MakeTToUnitFunc<_InType>(_Func); 4987 } 4988 }; 4989 4990 template<> 4991 class _Continuation_func_transformer<void, void> 4992 { 4993 public: 4994 static auto _Perform(std::function<HRESULT(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func)) 4995 { 4996 return details::_MakeUnitToUnitFunc(_Func); 4997 } 4998 }; 4999 /// <summary> 5000 /// The task handle type used to create a 'continuation task'. 5001 /// </summary> 5002 template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection> 5003 struct _ContinuationTaskHandle : 5004 details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type, 5005 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase> 5006 { 5007 typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType; 5008 5009 typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl; 5010 _Function _M_function; 5011 5012 _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl, 5013 const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl, 5014 const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode _InliningMode) : 5015 #if _MSC_VER >= 1800 5016 details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type, 5017 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase> 5018 ::_PPLTaskHandle(_ContinuationImpl) 5019 , _M_ancestorTaskImpl(_AncestorImpl) 5020 , _M_function(_Func) 5021 #else 5022 _M_ancestorTaskImpl(_AncestorImpl), _PPLTaskHandle(_ContinuationImpl), _M_function(_Func) 5023 #endif 5024 { 5025 _M_isTaskBasedContinuation = _IsTaskBased::value; 5026 _M_continuationContext = _Context; 5027 _M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware()); 5028 _M_inliningMode = _InliningMode; 5029 } 5030 5031 virtual ~_ContinuationTaskHandle() {} 5032 5033 #if _MSC_VER >= 1800 5034 template <typename _Func, typename _Arg, typename _RetArg> 5035 auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value, _RetArg && _retArg) const -> decltype(_func(std::forward<_Arg>(_value), std::forward<_RetArg>(_retArg))) 5036 { 5037 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger); 5038 return _func(std::forward<_Arg>(_value), std::forward<_RetArg>(_retArg)); 5039 } 5040 #endif 5041 5042 void _Perform() const 5043 { 5044 _Continue(_IsTaskBased(), _TypeSelection()); 5045 } 5046 5047 #if _MSC_VER >= 1800 5048 void _SyncCancelAndPropagateException() const 5049 { 5050 if (_M_ancestorTaskImpl->_HasUserException()) 5051 { 5052 // If the ancestor encountered an exception, transfer the exception to the continuation 5053 // This traverses down the tree to propagate the exception. 5054 this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true); 5055 } 5056 else 5057 { 5058 // If the ancestor was canceled, then your own execution should be canceled. 5059 // This traverses down the tree to cancel it. 5060 this->_M_pTask->_Cancel(true); 5061 } 5062 } 5063 #endif 5064 5065 // 5066 // Overload 0-0: _InternalReturnType -> _TaskType 5067 // 5068 // This is a straight task continuation which simply invokes its target with the ancestor's completion argument 5069 // 5070 void _Continue(std::false_type, details::_TypeSelectorNoAsync) const 5071 { 5072 _NormalizedContinuationReturnType retVal; 5073 #if _MSC_VER >= 1800 5074 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal); 5075 #else 5076 HRESULT hr =_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal); 5077 #endif 5078 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5079 _M_pTask->_FinalizeAndRunContinuations(retVal); 5080 } 5081 5082 // 5083 // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>* 5084 // or 5085 // _InternalReturnType -> task<_TaskType> 5086 // 5087 // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation 5088 // Depending on the output type, the right _AsyncInit gets invoked 5089 // 5090 void _Continue(std::false_type, details::_TypeSelectorAsyncTask) const 5091 { 5092 typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; 5093 _FuncOutputType retVal; 5094 #if _MSC_VER >= 1800 5095 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal); 5096 #else 5097 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal); 5098 #endif 5099 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5100 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( 5101 _M_pTask, 5102 retVal 5103 ); 5104 } 5105 void _Continue(std::false_type, details::_TypeSelectorAsyncOperation) const 5106 { 5107 typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; 5108 _FuncOutputType retVal; 5109 #if _MSC_VER >= 1800 5110 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal); 5111 #else 5112 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal); 5113 #endif 5114 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5115 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( 5116 _M_pTask, 5117 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_ContinuationReturnType>>(retVal).Get()); 5118 } 5119 5120 // 5121 // Overload 0-2: _InternalReturnType -> IAsyncAction* 5122 // 5123 // This is a straight task continuation which returns an async action which will be unwrapped for continuation 5124 // 5125 void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const 5126 { 5127 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; 5128 _FuncOutputType retVal; 5129 #if _MSC_VER >= 1800 5130 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &retVal); 5131 #else 5132 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &retVal); 5133 #endif 5134 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5135 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( 5136 _M_pTask, 5137 Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>( 5138 retVal).Get()); 5139 } 5140 5141 // 5142 // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>* 5143 // 5144 // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation 5145 // 5146 void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const 5147 { 5148 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; 5149 5150 _FuncOutputType _OpWithProgress; 5151 #if _MSC_VER >= 1800 5152 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &_OpWithProgress); 5153 #else 5154 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &_OpWithProgress); 5155 #endif 5156 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType; 5157 5158 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5159 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( 5160 _M_pTask, 5161 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(_OpWithProgress).Get()); 5162 } 5163 5164 // 5165 // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>* 5166 // 5167 // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation 5168 // 5169 void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const 5170 { 5171 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType; 5172 5173 _FuncOutputType _OpWithProgress; 5174 #if _MSC_VER >= 1800 5175 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult(), &_OpWithProgress); 5176 #else 5177 HRESULT hr = _Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function)(_M_ancestorTaskImpl->_GetResult(), &_OpWithProgress); 5178 #endif 5179 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType; 5180 5181 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5182 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>( 5183 _M_pTask, 5184 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(_OpWithProgress).Get()); 5185 } 5186 5187 5188 // 5189 // Overload 1-0: task<_InternalReturnType> -> _TaskType 5190 // 5191 // This is an exception handling type of continuation which takes the task rather than the task's result. 5192 // 5193 void _Continue(std::true_type, details::_TypeSelectorNoAsync) const 5194 { 5195 typedef task<_InternalReturnType> _FuncInputType; 5196 task<_InternalReturnType> _ResultTask; 5197 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5198 _NormalizedContinuationReturnType retVal; 5199 #if _MSC_VER >= 1800 5200 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask), &retVal); 5201 #else 5202 HRESULT hr = _Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function)(std::move(_ResultTask), &retVal); 5203 #endif 5204 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5205 _M_pTask->_FinalizeAndRunContinuations(retVal); 5206 } 5207 5208 // 5209 // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^ 5210 // or 5211 // task<_TaskType> 5212 // 5213 // This is an exception handling type of continuation which takes the task rather than 5214 // the task's result. It also returns an async operation or a task which will be unwrapped 5215 // for continuation 5216 // 5217 void _Continue(std::true_type, details::_TypeSelectorAsyncTask) const 5218 { 5219 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. 5220 task<_InternalReturnType> _ResultTask; 5221 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5222 _ContinuationReturnType retVal; 5223 #if _MSC_VER >= 1800 5224 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal); 5225 #else 5226 HRESULT hr = _M_function(std::move(_ResultTask), &retVal); 5227 #endif 5228 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5229 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, retVal); 5230 } 5231 void _Continue(std::true_type, details::_TypeSelectorAsyncOperation) const 5232 { 5233 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. 5234 task<_InternalReturnType> _ResultTask; 5235 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5236 _ContinuationReturnType retVal; 5237 #if _MSC_VER >= 1800 5238 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal); 5239 #else 5240 HRESULT hr = _M_function(std::move(_ResultTask), &retVal); 5241 #endif 5242 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5243 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, 5244 Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_ContinuationReturnType>>(retVal)); 5245 } 5246 5247 // 5248 // Overload 1-2: task<_InternalReturnType> -> IAsyncAction* 5249 // 5250 // This is an exception handling type of continuation which takes the task rather than 5251 // the task's result. It also returns an async action which will be unwrapped for continuation 5252 // 5253 void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const 5254 { 5255 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. 5256 task<_InternalReturnType> _ResultTask; 5257 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5258 _ContinuationReturnType retVal; 5259 #if _MSC_VER >= 1800 5260 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal); 5261 #else 5262 HRESULT hr = _M_function(std::move(_ResultTask), &retVal); 5263 #endif 5264 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5265 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, 5266 Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(retVal)); 5267 } 5268 5269 // 5270 // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>* 5271 // 5272 // This is an exception handling type of continuation which takes the task rather than 5273 // the task's result. It also returns an async operation with progress which will be unwrapped 5274 // for continuation 5275 // 5276 void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const 5277 { 5278 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. 5279 task<_InternalReturnType> _ResultTask; 5280 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5281 5282 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType; 5283 _ContinuationReturnType retVal; 5284 #if _MSC_VER >= 1800 5285 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal); 5286 #else 5287 HRESULT hr = _M_function(std::move(_ResultTask), &retVal); 5288 #endif 5289 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5290 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, 5291 Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>>(retVal)); 5292 } 5293 5294 // 5295 // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>* 5296 // 5297 // This is an exception handling type of continuation which takes the task rather than 5298 // the task's result. It also returns an async operation with progress which will be unwrapped 5299 // for continuation 5300 // 5301 void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const 5302 { 5303 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task. 5304 task<_InternalReturnType> _ResultTask; 5305 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl)); 5306 5307 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType; 5308 _ContinuationReturnType retVal; 5309 #if _MSC_VER >= 1800 5310 HRESULT hr = _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask), &retVal); 5311 #else 5312 HRESULT hr = _M_function(std::move(_ResultTask), &retVal); 5313 #endif 5314 if (FAILED(hr)) throw std::make_exception_ptr(hr); 5315 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(_M_pTask, 5316 Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>>(retVal)); 5317 } 5318 }; 5319 /// <summary> 5320 /// Initializes a task using a lambda, function pointer or function object. 5321 /// </summary> 5322 template<typename _InternalReturnType, typename _Function> 5323 void _TaskInitWithFunctor(const _Function& _Func) 5324 { 5325 typedef details::_InitFunctorTypeTraits<_InternalReturnType, details::_FunctionTypeTraits<_Function, void>::_FuncRetType> _Async_type_traits; 5326 5327 _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask; 5328 _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync; 5329 #if _MSC_VER >= 1800 5330 _M_Impl->_M_taskEventLogger._LogScheduleTask(false); 5331 #endif 5332 _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), Concurrency::details::_NoInline); 5333 } 5334 5335 /// <summary> 5336 /// Initializes a task using a task completion event. 5337 /// </summary> 5338 void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event) 5339 { 5340 _Event._RegisterTask(_M_Impl); 5341 } 5342 5343 /// <summary> 5344 /// Initializes a task using an asynchronous operation IAsyncOperation<T>* 5345 /// </summary> 5346 template<typename _Result, typename _OpType, typename _CompHandlerType, typename _ResultType> 5347 void _TaskInitAsyncOp(details::_AsyncInfoImpl<_OpType, _CompHandlerType, _ResultType>* _AsyncOp) 5348 { 5349 _M_Impl->_M_fFromAsync = true; 5350 #if _MSC_VER < 1800 5351 _M_Impl->_SetScheduledEvent(); 5352 #endif 5353 // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit 5354 // returns a completion could execute concurrently and the task must be fully initialized before that happens. 5355 _M_Impl->_M_TaskState = details::_Task_impl_base::_Started; 5356 // Pass the shared pointer into _AsyncInit for storage in the Async Callback. 5357 details::_Task_impl_base::_AsyncInit<_ReturnType, _Result>(_M_Impl, _AsyncOp); 5358 } 5359 5360 /// <summary> 5361 /// Initializes a task using an asynchronous operation IAsyncOperation<T>* 5362 /// </summary> 5363 template<typename _Result> 5364 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperation<_Result>* _AsyncOp) 5365 { 5366 _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationToAsyncOperationConverter<_Result>>(_AsyncOp).Get()); 5367 } 5368 5369 /// <summary> 5370 /// Initializes a task using an asynchronous operation with progress IAsyncOperationWithProgress<T, P>* 5371 /// </summary> 5372 template<typename _Result, typename _Progress> 5373 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncOperationWithProgress<_Result, _Progress>* _AsyncOp) 5374 { 5375 _TaskInitAsyncOp<_Result>(Microsoft::WRL::Make<details::_IAsyncOperationWithProgressToAsyncOperationConverter<_Result, _Progress>>(_AsyncOp).Get()); 5376 } 5377 /// <summary> 5378 /// Initializes a task using a callable object. 5379 /// </summary> 5380 template<typename _Function> 5381 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type) 5382 { 5383 _TaskInitWithFunctor<_ReturnType, _Function>(_Func); 5384 } 5385 5386 /// <summary> 5387 /// Initializes a task using a non-callable object. 5388 /// </summary> 5389 template<typename _Ty> 5390 void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type) 5391 { 5392 _TaskInitNoFunctor(_Param); 5393 } 5394 #if _MSC_VER >= 1800 5395 template<typename _InternalReturnType, typename _Function> 5396 auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType 5397 { 5398 if (!_M_Impl) 5399 { 5400 throw Concurrency::invalid_operation("then() cannot be called on a default constructed task."); 5401 } 5402 5403 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 5404 auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler(); 5405 auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack(); 5406 return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack); 5407 } 5408 #endif 5409 /// <summary> 5410 /// The one and only implementation of then for void and non-void tasks. 5411 /// </summary> 5412 template<typename _InternalReturnType, typename _Function> 5413 #if _MSC_VER >= 1800 5414 auto _ThenImpl(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, Concurrency::scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack, 5415 details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType 5416 #else 5417 auto _ThenImpl(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, 5418 bool _Aggregating = false, details::_TaskInliningMode _InliningMode = Concurrency::details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType 5419 #endif 5420 { 5421 if (_M_Impl == nullptr) 5422 { 5423 throw Concurrency::invalid_operation("then() cannot be called on a default constructed task."); 5424 } 5425 5426 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits; 5427 typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits; 5428 typedef typename _Async_type_traits::_TaskRetType _TaskType; 5429 5430 // 5431 // A **nullptr** token state indicates that it was not provided by the user. In this case, we inherit the antecedent's token UNLESS this is a 5432 // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user 5433 // explicitly passes the same token. 5434 // 5435 if (_PTokenState == nullptr) 5436 { 5437 #if _MSC_VER >= 1800 5438 if (_Function_type_traits::_Takes_task::value) 5439 #else 5440 if (_Function_type_traits::_Takes_task()) 5441 #endif 5442 { 5443 _PTokenState = Concurrency::details::_CancellationTokenState::_None(); 5444 } 5445 else 5446 { 5447 _PTokenState = _GetImpl()->_M_pTokenState; 5448 } 5449 } 5450 5451 task<_TaskType> _ContinuationTask; 5452 #if _MSC_VER >= 1800 5453 _ContinuationTask._CreateImpl(_PTokenState, _Scheduler); 5454 #else 5455 _ContinuationTask._CreateImpl(_PTokenState); 5456 #endif 5457 _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask); 5458 #if _MSC_VER < 1800 5459 _ContinuationTask._GetImpl()->_M_fRuntimeAggregate = _Aggregating; 5460 #endif 5461 _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync; 5462 #if _MSC_VER >= 1800 5463 _ContinuationTask._SetTaskCreationCallstack(_CreationStack); 5464 #endif 5465 _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>( 5466 _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode)); 5467 5468 return _ContinuationTask; 5469 } 5470 5471 // The underlying implementation for this task 5472 typename details::_Task_ptr<_ReturnType>::_Type _M_Impl; 5473 }; 5474 5475 /// <summary> 5476 /// The Parallel Patterns Library (PPL) <c>task</c> class. A <c>task</c> object represents work that can be executed asynchronously, 5477 /// and concurrently with other tasks and parallel work produced by parallel algorithms in the Concurrency Runtime. It produces 5478 /// a result of type <typeparamref name="_ResultType"/> on successful completion. Tasks of type <c>task<void></c> produce no result. 5479 /// A task can be waited upon and canceled independently of other tasks. It can also be composed with other tasks using 5480 /// continuations(<c>then</c>), and join(<c>when_all</c>) and choice(<c>when_any</c>) patterns. 5481 /// </summary> 5482 /// <remarks> 5483 /// For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>. 5484 /// </remarks> 5485 /**/ 5486 template<> 5487 class task<void> 5488 { 5489 public: 5490 /// <summary> 5491 /// The type of the result an object of this class produces. 5492 /// </summary> 5493 /**/ 5494 typedef void result_type; 5495 5496 /// <summary> 5497 /// Constructs a <c>task</c> object. 5498 /// </summary> 5499 /// <remarks> 5500 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 5501 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 5502 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 5503 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 5504 /// completion event is set.</para> 5505 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 5506 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 5507 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 5508 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 5509 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 5510 /// and not when the lamda returns.</para> 5511 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 5512 /// without the need for locks.</para> 5513 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 5514 /// to Windows Store apps.</para> 5515 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5516 /// </remarks> 5517 /**/ 5518 task() : _M_unitTask() 5519 { 5520 // The default constructor should create a task with a nullptr impl. This is a signal that the 5521 // task is not usable and should throw if any wait(), get() or then() APIs are used. 5522 } 5523 #if _MSC_VER < 1800 5524 /// <summary> 5525 /// Constructs a <c>task</c> object. 5526 /// </summary> 5527 /// <typeparam name="_Ty"> 5528 /// The type of the parameter from which the task is to be constructed. 5529 /// </typeparam> 5530 /// <param name="_Param"> 5531 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c> 5532 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function 5533 /// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>, 5534 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. 5535 /// </param> 5536 /// <remarks> 5537 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 5538 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 5539 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 5540 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 5541 /// completion event is set.</para> 5542 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 5543 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 5544 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 5545 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 5546 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 5547 /// and not when the lamda returns.</para> 5548 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 5549 /// without the need for locks.</para> 5550 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 5551 /// to Windows Store apps.</para> 5552 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5553 /// </remarks> 5554 /**/ 5555 template<typename _Ty> 5556 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5557 explicit task(_Ty _Param) 5558 { 5559 details::_ValidateTaskConstructorArgs<void, _Ty>(_Param); 5560 5561 _M_unitTask._CreateImpl(Concurrency::cancellation_token::none()._GetImplValue()); 5562 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor. 5563 _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress()); 5564 5565 _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0)); 5566 } 5567 #endif 5568 /// <summary> 5569 /// Constructs a <c>task</c> object. 5570 /// </summary> 5571 /// <typeparam name="_Ty"> 5572 /// The type of the parameter from which the task is to be constructed. 5573 /// </typeparam> 5574 /// <param name="_Param"> 5575 /// The parameter from which the task is to be constructed. This could be a lambda, a function object, a <c>task_completion_event<result_type></c> 5576 /// object, or a Windows::Foundation::IAsyncInfo if you are using tasks in your Windows Store app. The lambda or function 5577 /// object should be a type equivalent to <c>std::function<X(void)></c>, where X can be a variable of type <c>result_type</c>, 5578 /// <c>task<result_type></c>, or a Windows::Foundation::IAsyncInfo in Windows Store apps. 5579 /// </param> 5580 /// <param name="_Token"> 5581 /// The cancellation token to associate with this task. A task created without a cancellation token cannot be canceled. It implicitly receives 5582 /// the token <c>cancellation_token::none()</c>. 5583 /// </param> 5584 /// <remarks> 5585 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 5586 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 5587 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 5588 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 5589 /// completion event is set.</para> 5590 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 5591 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 5592 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 5593 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 5594 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 5595 /// and not when the lamda returns.</para> 5596 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 5597 /// without the need for locks.</para> 5598 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 5599 /// to Windows Store apps.</para> 5600 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5601 /// </remarks> 5602 /**/ 5603 template<typename _Ty> 5604 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5605 #if _MSC_VER >= 1800 5606 explicit task(_Ty _Param, const task_options& _TaskOptions = task_options()) 5607 #else 5608 explicit task(_Ty _Param, Concurrency::cancellation_token _CancellationToken) 5609 #endif 5610 { 5611 details::_ValidateTaskConstructorArgs<void, _Ty>(_Param); 5612 #if _MSC_VER >= 1800 5613 _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler()); 5614 #else 5615 _M_unitTask._CreateImpl(_CancellationToken._GetImplValue()); 5616 #endif 5617 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of the task constructor. 5618 #if _MSC_VER >= 1800 5619 _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK()); 5620 #else 5621 _M_unitTask._SetTaskCreationAddressHint(_ReturnAddress()); 5622 #endif 5623 _TaskInitMaybeFunctor(_Param, details::_IsCallable<void>(_Param, 0, 0, 0)); 5624 } 5625 5626 /// <summary> 5627 /// Constructs a <c>task</c> object. 5628 /// </summary> 5629 /// <param name="_Other"> 5630 /// The source <c>task</c> object. 5631 /// </param> 5632 /// <remarks> 5633 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 5634 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 5635 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 5636 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 5637 /// completion event is set.</para> 5638 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 5639 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 5640 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 5641 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 5642 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 5643 /// and not when the lamda returns.</para> 5644 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 5645 /// without the need for locks.</para> 5646 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 5647 /// to Windows Store apps.</para> 5648 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5649 /// </remarks> 5650 /**/ 5651 task(const task& _Other) : _M_unitTask(_Other._M_unitTask){} 5652 5653 /// <summary> 5654 /// Constructs a <c>task</c> object. 5655 /// </summary> 5656 /// <param name="_Other"> 5657 /// The source <c>task</c> object. 5658 /// </param> 5659 /// <remarks> 5660 /// The default constructor for a <c>task</c> is only present in order to allow tasks to be used within containers. 5661 /// A default constructed task cannot be used until you assign a valid task to it. Methods such as <c>get</c>, <c>wait</c> or <c>then</c> 5662 /// will throw an <see cref="invalid_argument Class">invalid_argument</see> exception when called on a default constructed task. 5663 /// <para>A task that is created from a <c>task_completion_event</c> will complete (and have its continuations scheduled) when the task 5664 /// completion event is set.</para> 5665 /// <para>The version of the constructor that takes a cancellation token creates a task that can be canceled using the 5666 /// <c>cancellation_token_source</c> the token was obtained from. Tasks created without a cancellation token are not cancelable.</para> 5667 /// <para>Tasks created from a <c>Windows::Foundation::IAsyncInfo</c> interface or a lambda that returns an <c>IAsyncInfo</c> interface 5668 /// reach their terminal state when the enclosed Windows Runtime asynchronous operation or action completes. Similarly, tasks created 5669 /// from a lamda that returns a <c>task<result_type></c> reach their terminal state when the inner task reaches its terminal state, 5670 /// and not when the lamda returns.</para> 5671 /// <para><c>task</c> behaves like a smart pointer and is safe to pass around by value. It can be accessed by multiple threads 5672 /// without the need for locks.</para> 5673 /// <para>The constructor overloads that take a Windows::Foundation::IAsyncInfo interface or a lambda returning such an interface, are only available 5674 /// to Windows Store apps.</para> 5675 /// <para>For more information, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5676 /// </remarks> 5677 /**/ 5678 task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {} 5679 5680 /// <summary> 5681 /// Replaces the contents of one <c>task</c> object with another. 5682 /// </summary> 5683 /// <param name="_Other"> 5684 /// The source <c>task</c> object. 5685 /// </param> 5686 /// <remarks> 5687 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same 5688 /// actual task as <paramref name="_Other"/> does. 5689 /// </remarks> 5690 /**/ 5691 task& operator=(const task& _Other) 5692 { 5693 if (this != &_Other) 5694 { 5695 _M_unitTask = _Other._M_unitTask; 5696 } 5697 return *this; 5698 } 5699 5700 /// <summary> 5701 /// Replaces the contents of one <c>task</c> object with another. 5702 /// </summary> 5703 /// <param name="_Other"> 5704 /// The source <c>task</c> object. 5705 /// </param> 5706 /// <remarks> 5707 /// As <c>task</c> behaves like a smart pointer, after a copy assignment, this <c>task</c> objects represents the same 5708 /// actual task as <paramref name="_Other"/> does. 5709 /// </remarks> 5710 /**/ 5711 task& operator=(task&& _Other) 5712 { 5713 if (this != &_Other) 5714 { 5715 _M_unitTask = std::move(_Other._M_unitTask); 5716 } 5717 return *this; 5718 } 5719 #if _MSC_VER < 1800 5720 /// <summary> 5721 /// Adds a continuation task to this task. 5722 /// </summary> 5723 /// <typeparam name="_Function"> 5724 /// The type of the function object that will be invoked by this task. 5725 /// </typeparam> 5726 /// <param name="_Func"> 5727 /// The continuation function to execute when this task completes. This continuation function must take as input 5728 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 5729 /// of the result this task produces. 5730 /// </param> 5731 /// <returns> 5732 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 5733 /// </returns> 5734 /// <remarks> 5735 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 5736 /// to Windows Store apps. 5737 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5738 /// </remarks> 5739 /**/ 5740 template<typename _Function> 5741 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5742 auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5743 { 5744 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, task_continuation_context::use_default()); 5745 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 5746 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 5747 return _ContinuationTask; 5748 } 5749 #endif 5750 /// <summary> 5751 /// Adds a continuation task to this task. 5752 /// </summary> 5753 /// <typeparam name="_Function"> 5754 /// The type of the function object that will be invoked by this task. 5755 /// </typeparam> 5756 /// <param name="_Func"> 5757 /// The continuation function to execute when this task completes. This continuation function must take as input 5758 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 5759 /// of the result this task produces. 5760 /// </param> 5761 /// <param name="_CancellationToken"> 5762 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit 5763 /// the token of its antecedent task. 5764 /// </param> 5765 /// <returns> 5766 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 5767 /// </returns> 5768 /// <remarks> 5769 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 5770 /// to Windows Store apps. 5771 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5772 /// </remarks> 5773 /**/ 5774 template<typename _Function> 5775 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5776 #if _MSC_VER >= 1800 5777 auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5778 { 5779 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 5780 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions); 5781 } 5782 #else 5783 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5784 { 5785 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), task_continuation_context::use_default()); 5786 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 5787 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 5788 return _ContinuationTask; 5789 } 5790 /// <summary> 5791 /// Adds a continuation task to this task. 5792 /// </summary> 5793 /// <typeparam name="_Function"> 5794 /// The type of the function object that will be invoked by this task. 5795 /// </typeparam> 5796 /// <param name="_Func"> 5797 /// The continuation function to execute when this task completes. This continuation function must take as input 5798 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 5799 /// of the result this task produces. 5800 /// </param> 5801 /// <param name="_ContinuationContext"> 5802 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a 5803 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see> 5804 /// </param> 5805 /// <returns> 5806 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 5807 /// </returns> 5808 /// <remarks> 5809 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 5810 /// to Windows Store apps. 5811 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5812 /// </remarks> 5813 /**/ 5814 template<typename _Function> 5815 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5816 auto then(const _Function& _Func, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5817 { 5818 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, nullptr, _ContinuationContext); 5819 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 5820 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 5821 return _ContinuationTask; 5822 5823 } 5824 #endif 5825 /// <summary> 5826 /// Adds a continuation task to this task. 5827 /// </summary> 5828 /// <typeparam name="_Function"> 5829 /// The type of the function object that will be invoked by this task. 5830 /// </typeparam> 5831 /// <param name="_Func"> 5832 /// The continuation function to execute when this task completes. This continuation function must take as input 5833 /// a variable of either <c>result_type</c> or <c>task<result_type></c>, where <c>result_type</c> is the type 5834 /// of the result this task produces. 5835 /// </param> 5836 /// <param name="_CancellationToken"> 5837 /// The cancellation token to associate with the continuation task. A continuation task that is created without a cancellation token will inherit 5838 /// the token of its antecedent task. 5839 /// </param> 5840 /// <param name="_ContinuationContext"> 5841 /// A variable that specifies where the continuation should execute. This variable is only useful when used in a 5842 /// Windows Store app. For more information, see <see cref="task_continuation_context Class">task_continuation_context</see> 5843 /// </param> 5844 /// <returns> 5845 /// The newly created continuation task. The result type of the returned task is determined by what <paramref name="_Func"/> returns. 5846 /// </returns> 5847 /// <remarks> 5848 /// The overloads of <c>then</c> that take a lambda or functor that returns a Windows::Foundation::IAsyncInfo interface, are only available 5849 /// to Windows Store apps. 5850 /// <para>For more information on how to use task continuations to compose asynchronous work, see <see cref="Task Parallelism (Concurrency Runtime)"/>.</para> 5851 /// </remarks> 5852 /**/ 5853 template<typename _Function> 5854 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 5855 #if _MSC_VER >= 1800 5856 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5857 { 5858 task_options _TaskOptions(_CancellationToken, _ContinuationContext); 5859 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 5860 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions); 5861 } 5862 #else 5863 auto then(const _Function& _Func, Concurrency::cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 5864 { 5865 auto _ContinuationTask = _M_unitTask._ThenImpl<void, _Function>(_Func, _CancellationToken._GetImplValue(), _ContinuationContext); 5866 // Do not move the next line out of this function. It is important that _ReturnAddress() evaluate to the the call site of then. 5867 _ContinuationTask._SetTaskCreationAddressHint(_ReturnAddress()); 5868 return _ContinuationTask; 5869 } 5870 #endif 5871 5872 /// <summary> 5873 /// Waits for this task to reach a terminal state. It is possible for <c>wait</c> to execute the task inline, if all of the tasks 5874 /// dependencies are satisfied, and it has not already been picked up for execution by a background worker. 5875 /// </summary> 5876 /// <returns> 5877 /// A <c>task_status</c> value which could be either <c>completed</c> or <c>canceled</c>. If the task encountered an exception 5878 /// during execution, or an exception was propagated to it from an antecedent task, <c>wait</c> will throw that exception. 5879 /// </returns> 5880 /**/ 5881 task_status wait() const 5882 { 5883 return _M_unitTask.wait(); 5884 } 5885 5886 /// <summary> 5887 /// Returns the result this task produced. If the task is not in a terminal state, a call to <c>get</c> will wait for the task to 5888 /// finish. This method does not return a value when called on a task with a <c>result_type</c> of <c>void</c>. 5889 /// </summary> 5890 /// <remarks> 5891 /// If the task is canceled, a call to <c>get</c> will throw a <see cref="task_canceled Class">task_canceled</see> exception. If the task 5892 /// encountered an different exception or an exception was propagated to it from an antecedent task, a call to <c>get</c> will throw that exception. 5893 /// </remarks> 5894 /**/ 5895 void get() const 5896 { 5897 _M_unitTask.get(); 5898 } 5899 #if _MSC_VER >= 1800 5900 5901 /// <summary> 5902 /// Determines if the task is completed. 5903 /// </summary> 5904 /// <returns> 5905 /// True if the task has completed, false otherwise. 5906 /// </returns> 5907 /// <remarks> 5908 /// The function returns true if the task is completed or canceled (with or without user exception). 5909 /// </remarks> 5910 bool is_done() const 5911 { 5912 return _M_unitTask.is_done(); 5913 } 5914 5915 /// <summary> 5916 /// Returns the scheduler for this task 5917 /// </summary> 5918 /// <returns> 5919 /// A pointer to the scheduler 5920 /// </returns> 5921 Concurrency::scheduler_ptr scheduler() const 5922 { 5923 return _M_unitTask.scheduler(); 5924 } 5925 #endif 5926 /// <summary> 5927 /// Determines whether the task unwraps a Windows Runtime <c>IAsyncInfo</c> interface or is descended from such a task. 5928 /// </summary> 5929 /// <returns> 5930 /// <c>true</c> if the task unwraps an <c>IAsyncInfo</c> interface or is descended from such a task, <c>false</c> otherwise. 5931 /// </returns> 5932 /**/ 5933 bool is_apartment_aware() const 5934 { 5935 return _M_unitTask.is_apartment_aware(); 5936 } 5937 5938 /// <summary> 5939 /// Determines whether two <c>task</c> objects represent the same internal task. 5940 /// </summary> 5941 /// <returns> 5942 /// <c>true</c> if the objects refer to the same underlying task, and <c>false</c> otherwise. 5943 /// </returns> 5944 /**/ 5945 bool operator==(const task<void>& _Rhs) const 5946 { 5947 return (_M_unitTask == _Rhs._M_unitTask); 5948 } 5949 5950 /// <summary> 5951 /// Determines whether two <c>task</c> objects represent different internal tasks. 5952 /// </summary> 5953 /// <returns> 5954 /// <c>true</c> if the objects refer to different underlying tasks, and <c>false</c> otherwise. 5955 /// </returns> 5956 /**/ 5957 bool operator!=(const task<void>& _Rhs) const 5958 { 5959 return !operator==(_Rhs); 5960 } 5961 5962 /// <summary> 5963 /// Create an underlying task implementation. 5964 /// </summary> 5965 #if _MSC_VER >= 1800 5966 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct, Concurrency::scheduler_ptr _Scheduler) 5967 { 5968 _M_unitTask._CreateImpl(_Ct, _Scheduler); 5969 } 5970 #else 5971 void _CreateImpl(Concurrency::details::_CancellationTokenState * _Ct) 5972 { 5973 _M_unitTask._CreateImpl(_Ct); 5974 } 5975 #endif 5976 5977 /// <summary> 5978 /// Return the underlying implementation for this task. 5979 /// </summary> 5980 const details::_Task_ptr<details::_Unit_type>::_Type & _GetImpl() const 5981 { 5982 return _M_unitTask._M_Impl; 5983 } 5984 5985 /// <summary> 5986 /// Set the implementation of the task to be the supplied implementaion. 5987 /// </summary> 5988 void _SetImpl(const details::_Task_ptr<details::_Unit_type>::_Type & _Impl) 5989 { 5990 _M_unitTask._SetImpl(_Impl); 5991 } 5992 5993 /// <summary> 5994 /// Set the implementation of the task to be the supplied implementaion using a move instead of a copy. 5995 /// </summary> 5996 void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl) 5997 { 5998 _M_unitTask._SetImpl(std::move(_Impl)); 5999 } 6000 6001 /// <summary> 6002 /// Sets a property determining whether the task is apartment aware. 6003 /// </summary> 6004 void _SetAsync(bool _Async = true) 6005 { 6006 _M_unitTask._SetAsync(_Async); 6007 } 6008 6009 /// <summary> 6010 /// Sets a field in the task impl to the return address for calls to the task constructors and the then method. 6011 /// </summary> 6012 #if _MSC_VER >= 1800 6013 void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack) 6014 { 6015 _M_unitTask._SetTaskCreationCallstack(_callstack); 6016 } 6017 #else 6018 void _SetTaskCreationAddressHint(void* _Address) 6019 { 6020 _M_unitTask._SetTaskCreationAddressHint(_Address); 6021 } 6022 #endif 6023 6024 /// <summary> 6025 /// An internal version of then that takes additional flags and executes the continuation inline. Used for runtime internal continuations only. 6026 /// </summary> 6027 template<typename _Function> 6028 #if _MSC_VER >= 1800 6029 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, 6030 details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 6031 { 6032 // inherit from antecedent 6033 auto _Scheduler = _GetImpl()->_GetScheduler(); 6034 6035 return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Scheduler, _CAPTURE_CALLSTACK(), _InliningMode); 6036 } 6037 #else 6038 auto _Then(const _Function& _Func, Concurrency::details::_CancellationTokenState *_PTokenState, 6039 bool _Aggregating, details::_TaskInliningMode _InliningMode = Concurrency::details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType 6040 { 6041 return _M_unitTask._ThenImpl<void, _Function>(_Func, _PTokenState, task_continuation_context::use_default(), _Aggregating, _InliningMode); 6042 } 6043 #endif 6044 6045 private: 6046 template <typename T> friend class task; 6047 template <typename T> friend class task_completion_event; 6048 6049 /// <summary> 6050 /// Initializes a task using a task completion event. 6051 /// </summary> 6052 void _TaskInitNoFunctor(task_completion_event<void>& _Event) 6053 { 6054 _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent); 6055 } 6056 /// <summary> 6057 /// Initializes a task using an asynchronous action IAsyncAction* 6058 /// </summary> 6059 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncAction* _AsyncAction) 6060 { 6061 _M_unitTask._TaskInitAsyncOp<details::_Unit_type>(Microsoft::WRL::Make<details::_IAsyncActionToAsyncOperationConverter>(_AsyncAction).Get()); 6062 } 6063 6064 /// <summary> 6065 /// Initializes a task using an asynchronous action with progress IAsyncActionWithProgress<_P>* 6066 /// </summary> 6067 template<typename _P> 6068 void _TaskInitNoFunctor(ABI::Windows::Foundation::IAsyncActionWithProgress<_P>* _AsyncActionWithProgress) 6069 { 6070 _M_unitTask._TaskInitAsyncOp<details::_Unit_type>(Microsoft::WRL::Make<details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>>(_AsyncActionWithProgress).Get()); 6071 } 6072 /// <summary> 6073 /// Initializes a task using a callable object. 6074 /// </summary> 6075 template<typename _Function> 6076 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type) 6077 { 6078 _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func); 6079 } 6080 6081 /// <summary> 6082 /// Initializes a task using a non-callable object. 6083 /// </summary> 6084 template<typename _T> 6085 void _TaskInitMaybeFunctor(_T & _Param, std::false_type) 6086 { 6087 _TaskInitNoFunctor(_Param); 6088 } 6089 6090 // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results. 6091 task<details::_Unit_type> _M_unitTask; 6092 }; 6093 6094 namespace details 6095 { 6096 6097 /// <summary> 6098 /// The following type traits are used for the create_task function. 6099 /// </summary> 6100 6101 // Unwrap task<T> 6102 template<typename _Ty> 6103 _Ty _GetUnwrappedType(task<_Ty>); 6104 6105 // Unwrap all supported types 6106 template<typename _Ty> 6107 auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg)); 6108 // fallback 6109 template<typename _Ty> 6110 _Ty _GetUnwrappedReturnType(_Ty, ...); 6111 6112 /// <summary> 6113 /// <c>_GetTaskType</c> functions will retrieve task type <c>T</c> in <c>task[T](Arg)</c>, 6114 /// for given constructor argument <c>Arg</c> and its property "callable". 6115 /// It will automatically unwrap argument to get the final return type if necessary. 6116 /// </summary> 6117 6118 // Non-Callable 6119 template<typename _Ty> 6120 _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type); 6121 6122 // Non-Callable 6123 template<typename _Ty> 6124 auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc)); 6125 6126 // Callable 6127 template<typename _Ty> 6128 auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(stdx::declval<_FunctionTypeTraits<_Ty, void>::_FuncRetType>(), 0)); 6129 6130 // Special callable returns void 6131 void _GetTaskType(std::function<HRESULT()>, std::true_type); 6132 struct _BadArgType{}; 6133 6134 template<typename _ReturnType, typename _Ty> 6135 auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable<_ReturnType>(_Param, 0, 0, 0))); 6136 6137 template<typename _ReturnType, typename _Ty> 6138 _BadArgType _FilterValidTaskType(_Ty _Param, ...); 6139 6140 template<typename _ReturnType, typename _Ty> 6141 struct _TaskTypeFromParam 6142 { 6143 typedef decltype(_FilterValidTaskType<_ReturnType>(stdx::declval<_Ty>(), 0)) _Type; 6144 }; 6145 } 6146 6147 6148 /// <summary> 6149 /// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor. 6150 /// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks. 6151 /// </summary> 6152 /// <typeparam name="_Ty"> 6153 /// The type of the parameter from which the task is to be constructed. 6154 /// </typeparam> 6155 /// <param name="_Param"> 6156 /// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c> 6157 /// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app. 6158 /// </param> 6159 /// <returns> 6160 /// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>. 6161 /// </returns> 6162 /// <remarks> 6163 /// The first overload behaves like a task constructor that takes a single parameter. 6164 /// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not 6165 /// allowed to pass in a different <c>task</c> object as the first parameter.</para> 6166 /// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>, 6167 /// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>. 6168 /// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or 6169 /// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>. 6170 /// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor 6171 /// that returns either of those types, the created task will have type <c>task<void></c>.</para> 6172 /// </remarks> 6173 /// <seealso cref="task Class"/> 6174 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 6175 /**/ 6176 template<typename _ReturnType, typename _Ty> 6177 __declspec(noinline) 6178 #if _MSC_VER >= 1800 6179 auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> 6180 #else 6181 auto create_task(_Ty _Param) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> 6182 #endif 6183 { 6184 static_assert(!std::is_same<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type, details::_BadArgType>::value, 6185 "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event" 6186 ); 6187 #if _MSC_VER >= 1800 6188 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK()); 6189 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param, _TaskOptions); 6190 #else 6191 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param); 6192 // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining 6193 // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is 6194 // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code. 6195 _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress()); 6196 #endif 6197 return _CreatedTask; 6198 } 6199 6200 /// <summary> 6201 /// Creates a PPL <see cref="task Class">task</c> object. <c>create_task</c> can be used anywhere you would have used a task constructor. 6202 /// It is provided mainly for convenience, because it allows use of the <c>auto</c> keyword while creating tasks. 6203 /// </summary> 6204 /// <typeparam name="_Ty"> 6205 /// The type of the parameter from which the task is to be constructed. 6206 /// </typeparam> 6207 /// <param name="_Param"> 6208 /// The parameter from which the task is to be constructed. This could be a lambda or function object, a <c>task_completion_event</c> 6209 /// object, a different <c>task</c> object, or a Windows::Foundation::IAsyncInfo interface if you are using tasks in your Windows Store app. 6210 /// </param> 6211 /// <param name="_Token"> 6212 /// The cancellation token to associate with the task. When the source for this token is canceled, cancellation will be requested on the task. 6213 /// </param> 6214 /// <returns> 6215 /// A new task of type <c>T</c>, that is inferred from <paramref name="_Param"/>. 6216 /// </returns> 6217 /// <remarks> 6218 /// The first overload behaves like a task constructor that takes a single parameter. 6219 /// <para>The second overload associates the cancellation token provided with the newly created task. If you use this overload you are not 6220 /// allowed to pass in a different <c>task</c> object as the first parameter.</para> 6221 /// <para>The type of the returned task is inferred from the first parameter to the function. If <paramref name="_Param"/> is a <c>task_completion_event<T></c>, 6222 /// a <c>task<T></c>, or a functor that returns either type <c>T</c> or <c>task<T></c>, the type of the created task is <c>task<T></c>. 6223 /// <para>In a Windows Store app, if <paramref name="_Param"/> is of type Windows::Foundation::IAsyncOperation<T>^ or 6224 /// Windows::Foundation::IAsyncOperationWithProgress<T,P>^, or a functor that returns either of those types, the created task will be of type <c>task<T></c>. 6225 /// If <paramref name="_Param"/> is of type Windows::Foundation::IAsyncAction^ or Windows::Foundation::IAsyncActionWithProgress<P>^, or a functor 6226 /// that returns either of those types, the created task will have type <c>task<void></c>.</para> 6227 /// </remarks> 6228 /// <seealso cref="task Class"/> 6229 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 6230 /**/ 6231 #if _MSC_VER >= 1800 6232 template<typename _ReturnType> 6233 __declspec(noinline) 6234 task<_ReturnType> create_task(const task<_ReturnType>& _Task) 6235 { 6236 task<_ReturnType> _CreatedTask(_Task); 6237 return _CreatedTask; 6238 } 6239 #else 6240 template<typename _ReturnType, typename _Ty> 6241 __declspec(noinline) 6242 auto create_task(_Ty _Param, Concurrency::cancellation_token _Token) -> task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> 6243 { 6244 static_assert(!std::is_same<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type, details::_BadArgType>::value, 6245 "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event" 6246 ); 6247 task<typename details::_TaskTypeFromParam<_ReturnType, _Ty>::_Type> _CreatedTask(_Param, _Token); 6248 // Ideally we would like to forceinline create_task, but __forceinline does nothing on debug builds. Therefore, we ask for no inlining 6249 // and overwrite the creation address hint set by the task constructor. DO NOT REMOVE this next line from create_task. It is 6250 // essential that _ReturnAddress() evaluate to the instruction right after the call to create_task in client code. 6251 _CreatedTask._SetTaskCreationAddressHint(_ReturnAddress()); 6252 return _CreatedTask; 6253 } 6254 #endif 6255 6256 namespace details 6257 { 6258 template<typename _T> 6259 task<typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperation<_T>*>()))>::type> _To_task_helper(ABI::Windows::Foundation::IAsyncOperation<_T>* op) 6260 { 6261 return task<_T>(op); 6262 } 6263 6264 template<typename _T, typename _Progress> 6265 task<typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<ABI::Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>*>()))>::type> _To_task_helper(ABI::Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>* op) 6266 { 6267 return task<_T>(op); 6268 } 6269 6270 inline task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncAction* op) 6271 { 6272 return task<void>(op); 6273 } 6274 6275 template<typename _Progress> 6276 task<void> _To_task_helper(ABI::Windows::Foundation::IAsyncActionWithProgress<_Progress>* op) 6277 { 6278 return task<void>(op); 6279 } 6280 6281 template<typename _ProgressType> 6282 class _ProgressDispatcherBase 6283 { 6284 public: 6285 6286 virtual ~_ProgressDispatcherBase() 6287 { 6288 } 6289 6290 virtual void _Report(const _ProgressType& _Val) = 0; 6291 }; 6292 6293 template<typename _ProgressType, typename _ClassPtrType> 6294 class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType> 6295 { 6296 public: 6297 6298 virtual ~_ProgressDispatcher() 6299 { 6300 } 6301 6302 _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr) 6303 { 6304 } 6305 6306 virtual void _Report(const _ProgressType& _Val) 6307 { 6308 _M_ptr->_FireProgress(_Val); 6309 } 6310 6311 private: 6312 6313 _ClassPtrType _M_ptr; 6314 }; 6315 } // namespace details 6316 6317 6318 /// <summary> 6319 /// The progress reporter class allows reporting progress notifications of a specific type. Each progress_reporter object is bound 6320 /// to a particular asynchronous action or operation. 6321 /// </summary> 6322 /// <typeparam name="_ProgressType"> 6323 /// The payload type of each progress notification reported through the progress reporter. 6324 /// </typeparam> 6325 /// <remarks> 6326 /// This type is only available to Windows Store apps. 6327 /// </remarks> 6328 /// <seealso cref="create_async Function"/> 6329 /**/ 6330 template<typename _ProgressType> 6331 class progress_reporter 6332 { 6333 typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType; 6334 6335 public: 6336 6337 /// <summary> 6338 /// Sends a progress report to the asynchronous action or operation to which this progress reporter is bound. 6339 /// </summary> 6340 /// <param name="_Val"> 6341 /// The payload to report through a progress notification. 6342 /// </param> 6343 /**/ 6344 void report(const _ProgressType& _Val) const 6345 { 6346 _M_dispatcher->_Report(_Val); 6347 } 6348 6349 template<typename _ClassPtrType> 6350 static progress_reporter _CreateReporter(_ClassPtrType _Ptr) 6351 { 6352 progress_reporter _Reporter; 6353 details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr); 6354 _Reporter._M_dispatcher = _PtrType(_PDispatcher); 6355 return _Reporter; 6356 } 6357 progress_reporter() {} 6358 6359 private: 6360 progress_reporter(details::_ProgressReporterCtorArgType); 6361 6362 _PtrType _M_dispatcher; 6363 }; 6364 6365 namespace details 6366 { 6367 // 6368 // maps internal definitions for AsyncStatus and defines states that are not client visible 6369 // 6370 enum _AsyncStatusInternal 6371 { 6372 _AsyncCreated = -1, // externally invisible 6373 // client visible states (must match AsyncStatus exactly) 6374 _AsyncStarted = ABI::Windows::Foundation::AsyncStatus::Started, // 0 6375 _AsyncCompleted = ABI::Windows::Foundation::AsyncStatus::Completed, // 1 6376 _AsyncCanceled = ABI::Windows::Foundation::AsyncStatus::Canceled, // 2 6377 _AsyncError = ABI::Windows::Foundation::AsyncStatus::Error, // 3 6378 // non-client visible internal states 6379 _AsyncCancelPending, 6380 _AsyncClosed, 6381 _AsyncUndefined 6382 }; 6383 6384 // 6385 // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results 6386 // (which are progressively consumable between Start state and before Close is called) 6387 // 6388 enum _AsyncResultType 6389 { 6390 SingleResult = 0x0001, 6391 MultipleResults = 0x0002 6392 }; 6393 6394 template<typename _T> 6395 struct _ProgressTypeTraits 6396 { 6397 static const bool _TakesProgress = false; 6398 typedef void _ProgressType; 6399 }; 6400 6401 template<typename _T> 6402 struct _ProgressTypeTraits<progress_reporter<_T>> 6403 { 6404 static const bool _TakesProgress = true; 6405 typedef typename _T _ProgressType; 6406 }; 6407 6408 template<typename _T, bool bTakesToken = std::is_same<_T, Concurrency::cancellation_token>::value, bool bTakesProgress = _ProgressTypeTraits<_T>::_TakesProgress> 6409 struct _TokenTypeTraits 6410 { 6411 static const bool _TakesToken = false; 6412 typedef typename _T _ReturnType; 6413 }; 6414 6415 template<typename _T> 6416 struct _TokenTypeTraits<_T, false, true> 6417 { 6418 static const bool _TakesToken = false; 6419 typedef void _ReturnType; 6420 }; 6421 6422 template<typename _T> 6423 struct _TokenTypeTraits<_T, true, false> 6424 { 6425 static const bool _TakesToken = true; 6426 typedef void _ReturnType; 6427 }; 6428 6429 template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount> 6430 struct _CAFunctorOptions 6431 { 6432 static const bool _TakesProgress = false; 6433 static const bool _TakesToken = false; 6434 typedef void _ProgressType; 6435 typedef void _ReturnType; 6436 }; 6437 6438 template<typename _T> 6439 struct _CAFunctorOptions<_T, 1> 6440 { 6441 private: 6442 6443 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; 6444 6445 public: 6446 6447 static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress; 6448 static const bool _TakesToken = _TokenTypeTraits<_Argument1Type>::_TakesToken; 6449 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; 6450 typedef typename _TokenTypeTraits<_Argument1Type>::_ReturnType _ReturnType; 6451 }; 6452 6453 template<typename _T> 6454 struct _CAFunctorOptions<_T, 2> 6455 { 6456 private: 6457 6458 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; 6459 typedef typename _FunctorTypeTraits<_T>::_Argument2Type _Argument2Type; 6460 6461 public: 6462 6463 static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress; 6464 static const bool _TakesToken = !_TakesProgress ? true : _TokenTypeTraits<_Argument2Type>::_TakesToken; 6465 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; 6466 typedef typename _TokenTypeTraits<_Argument2Type>::_ReturnType _ReturnType; 6467 }; 6468 6469 template<typename _T> 6470 struct _CAFunctorOptions<_T, 3> 6471 { 6472 private: 6473 6474 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type; 6475 6476 public: 6477 6478 static const bool _TakesProgress = true; 6479 static const bool _TakesToken = true; 6480 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType; 6481 typedef typename _FunctorTypeTraits<_T>::_Argument3Type _ReturnType; 6482 }; 6483 6484 class _Zip 6485 { 6486 }; 6487 6488 // *************************************************************************** 6489 // Async Operation Task Generators 6490 // 6491 6492 // 6493 // Functor returns an IAsyncInfo - result needs to be wrapped in a task: 6494 // 6495 template<typename _AsyncSelector, typename _ReturnType> 6496 struct _SelectorTaskGenerator 6497 { 6498 #if _MSC_VER >= 1800 6499 template<typename _Function> 6500 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6501 { 6502 task_options _taskOptinos(_Cts.get_token()); 6503 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6504 return task<_ReturnType>(_Func(_pRet), _taskOptinos); 6505 } 6506 6507 template<typename _Function> 6508 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6509 { 6510 task_options _taskOptinos(_Cts.get_token()); 6511 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6512 return task<_ReturnType>(_Func(_Cts.get_token(), _pRet), _taskOptinos); 6513 } 6514 6515 template<typename _Function, typename _ProgressObject> 6516 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6517 { 6518 task_options _taskOptinos(_Cts.get_token()); 6519 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6520 return task<_ReturnType>(_Func(_Progress, _pRet), _taskOptinos); 6521 } 6522 6523 template<typename _Function, typename _ProgressObject> 6524 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6525 { 6526 task_options _taskOptinos(_Cts.get_token()); 6527 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6528 return task<_ReturnType>(_Func(_Progress, _Cts.get_token(), _pRet), _taskOptinos); 6529 } 6530 #else 6531 template<typename _Function> 6532 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6533 { 6534 return task<_ReturnType>(_Func(_pRet), _Cts.get_token()); 6535 } 6536 6537 template<typename _Function> 6538 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6539 { 6540 return task<_ReturnType>(_Func(_Cts.get_token(), _pRet), _Cts.get_token()); 6541 } 6542 6543 template<typename _Function, typename _ProgressObject> 6544 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6545 { 6546 return task<_ReturnType>(_Func(_Progress, _pRet), _Cts.get_token()); 6547 } 6548 6549 template<typename _Function, typename _ProgressObject> 6550 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6551 { 6552 return task<_ReturnType>(_Func(_Progress, _Cts.get_token(), _pRet), _Cts.get_token()); 6553 } 6554 #endif 6555 }; 6556 6557 template<typename _AsyncSelector> 6558 struct _SelectorTaskGenerator<_AsyncSelector, void> 6559 { 6560 #if _MSC_VER >= 1800 6561 template<typename _Function> 6562 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6563 { 6564 task_options _taskOptinos(_Cts.get_token()); 6565 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6566 return task<void>(_Func(), _taskOptinos); 6567 } 6568 6569 template<typename _Function> 6570 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6571 { 6572 task_options _taskOptinos(_Cts.get_token()); 6573 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6574 return task<void>(_Func(_Cts.get_token()), _taskOptinos); 6575 } 6576 6577 template<typename _Function, typename _ProgressObject> 6578 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6579 { 6580 task_options _taskOptinos(_Cts.get_token()); 6581 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6582 return task<void>(_Func(_Progress), _taskOptinos); 6583 } 6584 6585 template<typename _Function, typename _ProgressObject> 6586 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6587 { 6588 task_options _taskOptinos(_Cts.get_token()); 6589 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6590 return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos); 6591 } 6592 #else 6593 template<typename _Function> 6594 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6595 { 6596 return task<void>(_Func(), _Cts.get_token()); 6597 } 6598 6599 template<typename _Function> 6600 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6601 { 6602 return task<void>(_Func(_Cts.get_token()), _Cts.get_token()); 6603 } 6604 6605 template<typename _Function, typename _ProgressObject> 6606 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6607 { 6608 return task<void>(_Func(_Progress), _Cts.get_token()); 6609 } 6610 6611 template<typename _Function, typename _ProgressObject> 6612 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6613 { 6614 return task<void>(_Func(_Progress, _Cts.get_token()), _Cts.get_token()); 6615 } 6616 #endif 6617 }; 6618 6619 #if _MSC_VER < 1800 6620 // For create_async lambdas that return a (non-task) result, we oversubscriber the current task for the duration of the 6621 // lambda. 6622 struct _Task_generator_oversubscriber 6623 { 6624 _Task_generator_oversubscriber() 6625 { 6626 Concurrency::details::_Context::_Oversubscribe(true); 6627 } 6628 6629 ~_Task_generator_oversubscriber() 6630 { 6631 Concurrency::details::_Context::_Oversubscribe(false); 6632 } 6633 }; 6634 #endif 6635 6636 // 6637 // Functor returns a result - it needs to be wrapped in a task: 6638 // 6639 template<typename _ReturnType> 6640 struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, _ReturnType> 6641 { 6642 #if _MSC_VER >= 1800 6643 6644 #pragma warning(push) 6645 #pragma warning(disable: 4702) 6646 template<typename _Function> 6647 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6648 { 6649 task_options _taskOptinos(_Cts.get_token()); 6650 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6651 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6652 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6653 (_Oversubscriber); 6654 HRESULT hr = _Func(_pRet); 6655 retVal = _pRet; 6656 return hr; 6657 }, _taskOptinos); 6658 } 6659 #pragma warning(pop) 6660 6661 template<typename _Function> 6662 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6663 { 6664 task_options _taskOptinos(_Cts.get_token()); 6665 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6666 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6667 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6668 (_Oversubscriber); 6669 HRESULT hr = _Func(_Cts.get_token(), _pRet); 6670 retVal = _pRet; 6671 return hr; 6672 }, _taskOptinos); 6673 } 6674 6675 template<typename _Function, typename _ProgressObject> 6676 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6677 { 6678 task_options _taskOptinos(_Cts.get_token()); 6679 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6680 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6681 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6682 (_Oversubscriber); 6683 HRESULT hr = _Func(_Progress, _pRet); 6684 retVal = _pRet; 6685 return hr; 6686 }, _taskOptinos); 6687 } 6688 6689 template<typename _Function, typename _ProgressObject> 6690 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6691 { 6692 task_options _taskOptinos(_Cts.get_token()); 6693 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6694 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6695 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6696 (_Oversubscriber); 6697 HRESULT hr = _Func(_Progress, _Cts.get_token(), _pRet); 6698 retVal = _pRet; 6699 return hr; 6700 }, _taskOptinos); 6701 } 6702 #else 6703 template<typename _Function> 6704 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6705 { 6706 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6707 _Task_generator_oversubscriber _Oversubscriber; 6708 HRESULT hr = _Func(_pRet); 6709 retVal = _pRet; 6710 return hr; 6711 }, _Cts.get_token()); 6712 } 6713 6714 template<typename _Function> 6715 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6716 { 6717 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6718 _Task_generator_oversubscriber _Oversubscriber; 6719 HRESULT hr = _Func(_Cts.get_token(), _pRet); 6720 retVal = _pRet; 6721 return hr; 6722 }, _Cts.get_token()); 6723 } 6724 6725 template<typename _Function, typename _ProgressObject> 6726 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6727 { 6728 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6729 _Task_generator_oversubscriber _Oversubscriber; 6730 HRESULT hr = _Func(_Progress, _pRet); 6731 retVal = _pRet; 6732 return hr; 6733 }, _Cts.get_token()); 6734 } 6735 6736 template<typename _Function, typename _ProgressObject> 6737 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6738 { 6739 return task<_ReturnType>([=](_ReturnType* retVal) -> HRESULT { 6740 _Task_generator_oversubscriber _Oversubscriber; 6741 HRESULT hr = _Func(_Progress, _Cts.get_token(), _pRet); 6742 retVal = _pRet; 6743 return hr; 6744 }, _Cts.get_token()); 6745 } 6746 #endif 6747 }; 6748 6749 template<> 6750 struct _SelectorTaskGenerator<details::_TypeSelectorNoAsync, void> 6751 { 6752 #if _MSC_VER >= 1800 6753 template<typename _Function> 6754 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6755 { 6756 task_options _taskOptinos(_Cts.get_token()); 6757 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6758 return task<void>([=]() -> HRESULT { 6759 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6760 (_Oversubscriber); 6761 return _Func(); 6762 }, _taskOptinos); 6763 } 6764 6765 template<typename _Function> 6766 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6767 { 6768 task_options _taskOptinos(_Cts.get_token()); 6769 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6770 return task<void>([=]() -> HRESULT { 6771 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6772 (_Oversubscriber); 6773 return _Func(_Cts.get_token()); 6774 }, _taskOptinos); 6775 } 6776 6777 template<typename _Function, typename _ProgressObject> 6778 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6779 { 6780 task_options _taskOptinos(_Cts.get_token()); 6781 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6782 return task<void>([=]() -> HRESULT { 6783 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6784 (_Oversubscriber); 6785 return _Func(_Progress); 6786 }, _taskOptinos); 6787 } 6788 6789 template<typename _Function, typename _ProgressObject> 6790 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6791 { 6792 task_options _taskOptinos(_Cts.get_token()); 6793 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack); 6794 return task<void>([=]() -> HRESULT { 6795 Concurrency::details::_Task_generator_oversubscriber_t _Oversubscriber; 6796 (_Oversubscriber); 6797 return _Func(_Progress, _Cts.get_token()); 6798 }, _taskOptinos); 6799 } 6800 #else 6801 template<typename _Function> 6802 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6803 { 6804 return task<void>([=]() -> HRESULT { 6805 _Task_generator_oversubscriber _Oversubscriber; 6806 return _Func(); 6807 }, _Cts.get_token()); 6808 } 6809 6810 template<typename _Function> 6811 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6812 { 6813 return task<void>([=]() -> HRESULT { 6814 _Task_generator_oversubscriber _Oversubscriber; 6815 return _Func(_Cts.get_token()); 6816 }, _Cts.get_token()); 6817 } 6818 6819 template<typename _Function, typename _ProgressObject> 6820 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6821 { 6822 return task<void>([=]() -> HRESULT { 6823 _Task_generator_oversubscriber _Oversubscriber; 6824 return _Func(_Progress); 6825 }, _Cts.get_token()); 6826 } 6827 6828 template<typename _Function, typename _ProgressObject> 6829 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6830 { 6831 return task<void>([=]() -> HRESULT { 6832 _Task_generator_oversubscriber _Oversubscriber; 6833 return _Func(_Progress, _Cts.get_token()); 6834 }, _Cts.get_token()); 6835 } 6836 #endif 6837 }; 6838 6839 // 6840 // Functor returns a task - the task can directly be returned: 6841 // 6842 template<typename _ReturnType> 6843 struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, _ReturnType> 6844 { 6845 template<typename _Function> 6846 #if _MSC_VER >= 1800 6847 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6848 #else 6849 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6850 #endif 6851 { 6852 task<_ReturnType> _task; 6853 _Func(&_task); 6854 return _task; 6855 } 6856 6857 template<typename _Function> 6858 #if _MSC_VER >= 1800 6859 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6860 #else 6861 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6862 #endif 6863 { 6864 task<_ReturnType> _task; 6865 _Func(_Cts.get_token(), &_task); 6866 return _task; 6867 } 6868 6869 template<typename _Function, typename _ProgressObject> 6870 #if _MSC_VER >= 1800 6871 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6872 #else 6873 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6874 #endif 6875 { 6876 task<_ReturnType> _task; 6877 _Func(_Progress, &_task); 6878 return _task; 6879 } 6880 6881 template<typename _Function, typename _ProgressObject> 6882 #if _MSC_VER >= 1800 6883 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6884 #else 6885 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6886 #endif 6887 { 6888 task<_ReturnType> _task; 6889 _Func(_Progress, _Cts.get_token(), &_task); 6890 return _task; 6891 } 6892 }; 6893 6894 template<> 6895 struct _SelectorTaskGenerator<details::_TypeSelectorAsyncTask, void> 6896 { 6897 template<typename _Function> 6898 #if _MSC_VER >= 1800 6899 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6900 #else 6901 static task<void> _GenerateTask_0(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6902 #endif 6903 { 6904 task<void> _task; 6905 _Func(&_task); 6906 return _task; 6907 } 6908 6909 template<typename _Function> 6910 #if _MSC_VER >= 1800 6911 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6912 #else 6913 static task<void> _GenerateTask_1C(const _Function& _Func, Concurrency::cancellation_token_source _Cts) 6914 #endif 6915 { 6916 task<void> _task; 6917 _Func(_Cts.get_token(), &_task); 6918 return _task; 6919 } 6920 6921 template<typename _Function, typename _ProgressObject> 6922 #if _MSC_VER >= 1800 6923 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6924 #else 6925 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6926 #endif 6927 { 6928 task<void> _task; 6929 _Func(_Progress, &_task); 6930 return _task; 6931 } 6932 6933 template<typename _Function, typename _ProgressObject> 6934 #if _MSC_VER >= 1800 6935 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6936 #else 6937 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, Concurrency::cancellation_token_source _Cts) 6938 #endif 6939 { 6940 task<void> _task; 6941 _Func(_Progress, _Cts.get_token(), &_task); 6942 return _task; 6943 } 6944 }; 6945 6946 template<typename _Generator, bool _TakesToken, bool TakesProgress> 6947 struct _TaskGenerator 6948 { 6949 }; 6950 6951 template<typename _Generator> 6952 struct _TaskGenerator<_Generator, false, false> 6953 { 6954 #if _MSC_VER >= 1800 6955 template<typename _Function, typename _ClassPtr, typename _ProgressType> 6956 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6957 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) 6958 { 6959 (void)_Ptr; 6960 return _Generator::_GenerateTask_0(_Func, _Cts, _callstack); 6961 } 6962 6963 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 6964 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 6965 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack)) 6966 { 6967 return _Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack); 6968 } 6969 #else 6970 template<typename _Function, typename _ClassPtr, typename _ProgressType> 6971 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 6972 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts)) 6973 { 6974 (void)_Ptr; 6975 return _Generator::_GenerateTask_0(_Func, _Cts); 6976 } 6977 6978 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 6979 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 6980 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet)) 6981 { 6982 return _Generator::_GenerateTask_0(_Func, _Cts, _pRet); 6983 } 6984 #endif 6985 }; 6986 6987 template<typename _Generator> 6988 struct _TaskGenerator<_Generator, true, false> 6989 { 6990 #if _MSC_VER >= 1800 6991 template<typename _Function, typename _ClassPtr, typename _ProgressType> 6992 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 6993 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) 6994 { 6995 return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack); 6996 } 6997 6998 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 6999 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7000 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack)) 7001 { 7002 return _Generator::_GenerateTask_1C(_Func, _Cts, _pRet, _callstack); 7003 } 7004 #else 7005 template<typename _Function, typename _ClassPtr, typename _ProgressType> 7006 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 7007 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts)) 7008 { 7009 return _Generator::_GenerateTask_1C(_Func, _Cts); 7010 } 7011 7012 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 7013 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7014 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet)) 7015 { 7016 return _Generator::_GenerateTask_1C(_Func, _Cts, _pRet); 7017 } 7018 #endif 7019 }; 7020 7021 template<typename _Generator> 7022 struct _TaskGenerator<_Generator, false, true> 7023 { 7024 #if _MSC_VER >= 1800 7025 template<typename _Function, typename _ClassPtr, typename _ProgressType> 7026 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 7027 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) 7028 { 7029 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); 7030 } 7031 7032 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 7033 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7034 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack)) 7035 { 7036 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet, _callstack); 7037 } 7038 #else 7039 template<typename _Function, typename _ClassPtr, typename _ProgressType> 7040 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 7041 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts)) 7042 { 7043 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts); 7044 } 7045 7046 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 7047 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7048 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet)) 7049 { 7050 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet); 7051 } 7052 #endif 7053 }; 7054 7055 template<typename _Generator> 7056 struct _TaskGenerator<_Generator, true, true> 7057 { 7058 #if _MSC_VER >= 1800 7059 template<typename _Function, typename _ClassPtr, typename _ProgressType> 7060 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 7061 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack)) 7062 { 7063 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack); 7064 } 7065 7066 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 7067 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7068 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet, _callstack)) 7069 { 7070 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet, _callstack); 7071 } 7072 #else 7073 template<typename _Function, typename _ClassPtr, typename _ProgressType> 7074 static auto _GenerateTaskNoRet(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 7075 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts)) 7076 { 7077 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts); 7078 } 7079 7080 template<typename _Function, typename _ClassPtr, typename _ProgressType, typename _ReturnType> 7081 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7082 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _pRet)) 7083 { 7084 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _pRet); 7085 } 7086 #endif 7087 }; 7088 7089 // *************************************************************************** 7090 // Async Operation Attributes Classes 7091 // 7092 // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in 7093 // a single container. An attribute class must define: 7094 // 7095 // Mandatory: 7096 // ------------------------- 7097 // 7098 // _AsyncBaseType : The Windows Runtime interface which is being implemented. 7099 // _CompletionDelegateType : The Windows Runtime completion delegate type for the interface. 7100 // _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type. 7101 // _ReturnType : The return type of the async construct (void for actions / non-void for operations) 7102 // 7103 // _TakesProgress : An indication as to whether or not 7104 // 7105 // _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task 7106 // 7107 // Optional: 7108 // ------------------------- 7109 // 7110 7111 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress> 7112 struct _AsyncAttributes 7113 { 7114 }; 7115 7116 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken> 7117 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true> 7118 { 7119 typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType; 7120 typedef typename ABI::Windows::Foundation::IAsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType; 7121 typedef typename ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType; 7122 typedef typename _ReturnType _ReturnType; 7123 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ReturnType_abi; 7124 typedef typename _ProgressType _ProgressType; 7125 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationWithProgressProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ProgressType_abi; 7126 typedef typename _TaskTraits::_AsyncKind _AsyncKind; 7127 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; 7128 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; 7129 7130 static const bool _TakesProgress = true; 7131 static const bool _TakesToken = _TakesToken; 7132 7133 template<typename _Function, typename _ClassPtr> 7134 #if _MSC_VER >= 1800 7135 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7136 { 7137 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi, _ReturnType>(_Func, _Ptr, _Cts, _pRet, _callstack); 7138 } 7139 #else 7140 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7141 { 7142 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi, _ReturnType>(_Func, _Ptr, _Cts, _pRet); 7143 } 7144 #endif 7145 }; 7146 7147 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken> 7148 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false> 7149 { 7150 typedef typename ABI::Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType; 7151 typedef _Zip _ProgressDelegateType; 7152 typedef typename ABI::Windows::Foundation::IAsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType; 7153 typedef typename _ReturnType _ReturnType; 7154 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncOperationSelector(stdx::declval<_AsyncBaseType*>()))>::type _ReturnType_abi; 7155 typedef typename _TaskTraits::_AsyncKind _AsyncKind; 7156 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; 7157 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; 7158 7159 static const bool _TakesProgress = false; 7160 static const bool _TakesToken = _TakesToken; 7161 7162 template<typename _Function, typename _ClassPtr> 7163 #if _MSC_VER >= 1800 7164 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7165 { 7166 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet, _callstack); 7167 } 7168 #else 7169 static task<typename _TaskTraits::_TaskRetType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7170 { 7171 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType, _ReturnType>(_Func, _Ptr, _Cts, _pRet); 7172 } 7173 #endif 7174 }; 7175 7176 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken> 7177 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true> 7178 { 7179 typedef typename ABI::Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType; 7180 typedef typename ABI::Windows::Foundation::IAsyncActionProgressHandler<_ProgressType> _ProgressDelegateType; 7181 typedef typename ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType; 7182 typedef void _ReturnType; 7183 typedef void _ReturnType_abi; 7184 typedef typename _ProgressType _ProgressType; 7185 typedef typename ABI::Windows::Foundation::Internal::GetAbiType<decltype(_UnwrapAsyncActionWithProgressSelector(stdx::declval<_AsyncBaseType*>()))>::type _ProgressType_abi; 7186 typedef typename _TaskTraits::_AsyncKind _AsyncKind; 7187 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; 7188 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator; 7189 7190 static const bool _TakesProgress = true; 7191 static const bool _TakesToken = _TakesToken; 7192 7193 #if _MSC_VER >= 1800 7194 template<typename _Function, typename _ClassPtr> 7195 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 7196 { 7197 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _callstack); 7198 } 7199 template<typename _Function, typename _ClassPtr> 7200 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7201 { 7202 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _pRet, _callstack); 7203 } 7204 #else 7205 template<typename _Function, typename _ClassPtr> 7206 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 7207 { 7208 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts); 7209 } 7210 template<typename _Function, typename _ClassPtr> 7211 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7212 { 7213 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType_abi>(_Func, _Ptr, _Cts, _pRet); 7214 } 7215 #endif 7216 }; 7217 7218 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken> 7219 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false> 7220 { 7221 typedef typename ABI::Windows::Foundation::IAsyncAction _AsyncBaseType; 7222 typedef _Zip _ProgressDelegateType; 7223 typedef typename ABI::Windows::Foundation::IAsyncActionCompletedHandler _CompletionDelegateType; 7224 typedef void _ReturnType; 7225 typedef void _ReturnType_abi; 7226 typedef typename _TaskTraits::_AsyncKind _AsyncKind; 7227 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator; 7228 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator; 7229 7230 static const bool _TakesProgress = false; 7231 static const bool _TakesToken = _TakesToken; 7232 7233 #if _MSC_VER >= 1800 7234 template<typename _Function, typename _ClassPtr> 7235 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack) 7236 { 7237 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack); 7238 } 7239 template<typename _Function, typename _ClassPtr> 7240 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet, const _TaskCreationCallstack & _callstack) 7241 { 7242 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _pRet, _callstack); 7243 } 7244 #else 7245 template<typename _Function, typename _ClassPtr> 7246 static task<void> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts) 7247 { 7248 return _TaskGenerator::_GenerateTaskNoRet<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts); 7249 } 7250 template<typename _Function, typename _ClassPtr> 7251 static task<task<void>> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, Concurrency::cancellation_token_source _Cts, _ReturnType* _pRet) 7252 { 7253 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _pRet); 7254 } 7255 #endif 7256 }; 7257 7258 template<typename _Function> 7259 struct _AsyncLambdaTypeTraits 7260 { 7261 typedef typename _Unhat<typename _CAFunctorOptions<_Function>::_ReturnType>::_Value _ReturnType; 7262 typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type; 7263 typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType; 7264 7265 static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress; 7266 static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken; 7267 7268 typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits; 7269 typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes; 7270 }; 7271 // *************************************************************************** 7272 // AsyncInfo (and completion) Layer: 7273 // 7274 #ifndef RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED 7275 #define RUNTIMECLASS_Concurrency_winrt_details__AsyncInfoBase_DEFINED 7276 extern const __declspec(selectany) WCHAR RuntimeClass_Concurrency_winrt_details__AsyncInfoBase[] = L"Concurrency_winrt.details._AsyncInfoBase"; 7277 #endif 7278 7279 // 7280 // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations) 7281 // 7282 template < typename _Attributes, _AsyncResultType resultType = SingleResult > 7283 class _AsyncInfoBase abstract : public Microsoft::WRL::RuntimeClass< 7284 Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRt>, Microsoft::WRL::Implements<typename _Attributes::_AsyncBaseType, ABI::Windows::Foundation::IAsyncInfo>> 7285 { 7286 InspectableClass(RuntimeClass_Concurrency_winrt_details__AsyncInfoBase, BaseTrust) 7287 public: 7288 _AsyncInfoBase() : 7289 _M_currentStatus(_AsyncStatusInternal::_AsyncCreated), 7290 _M_errorCode(S_OK), 7291 _M_completeDelegate(nullptr), 7292 _M_CompleteDelegateAssigned(0), 7293 _M_CallbackMade(0) 7294 { 7295 #if _MSC_VER < 1800 7296 _M_id = Concurrency::details::_GetNextAsyncId(); 7297 #else 7298 _M_id = Concurrency::details::platform::GetNextAsyncId(); 7299 #endif 7300 } 7301 public: 7302 virtual STDMETHODIMP GetResults(typename _Attributes::_ReturnType_abi* results) 7303 { 7304 (void)results; 7305 return E_UNEXPECTED; 7306 } 7307 7308 virtual STDMETHODIMP get_Id(unsigned int* id) 7309 { 7310 HRESULT hr = _CheckValidStateForAsyncInfoCall(); 7311 if (FAILED(hr)) return hr; 7312 if (!id) return E_POINTER; 7313 *id = _M_id; 7314 return S_OK; 7315 } 7316 7317 virtual STDMETHODIMP put_Id(unsigned int id) 7318 { 7319 HRESULT hr = _CheckValidStateForAsyncInfoCall(); 7320 if (FAILED(hr)) return hr; 7321 7322 if (id == 0) 7323 { 7324 return E_INVALIDARG; 7325 } 7326 else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated) 7327 { 7328 return E_ILLEGAL_METHOD_CALL; 7329 } 7330 7331 _M_id = id; 7332 return S_OK; 7333 } 7334 virtual STDMETHODIMP get_Status(ABI::Windows::Foundation::AsyncStatus* status) 7335 { 7336 HRESULT hr = _CheckValidStateForAsyncInfoCall(); 7337 if (FAILED(hr)) return hr; 7338 if (!status) return E_POINTER; 7339 7340 _AsyncStatusInternal _Current = _M_currentStatus; 7341 // 7342 // Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but 7343 // can still transition to "completed" if the operation completes without acknowledging the cancellation request 7344 // 7345 switch (_Current) 7346 { 7347 case _AsyncCancelPending: 7348 _Current = _AsyncCanceled; 7349 break; 7350 case _AsyncCreated: 7351 _Current = _AsyncStarted; 7352 break; 7353 default: 7354 break; 7355 } 7356 7357 *status = static_cast<ABI::Windows::Foundation::AsyncStatus>(_Current); 7358 return S_OK; 7359 } 7360 7361 virtual STDMETHODIMP get_ErrorCode(HRESULT* errorCode) 7362 { 7363 HRESULT hr = _CheckValidStateForAsyncInfoCall(); 7364 if (FAILED(hr)) return hr; 7365 if (!hr) return hr; 7366 *errorCode = _M_errorCode; 7367 return S_OK; 7368 } 7369 7370 virtual STDMETHODIMP get_Progress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) 7371 { 7372 return _GetOnProgress(_ProgressHandler); 7373 } 7374 7375 virtual STDMETHODIMP put_Progress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) 7376 { 7377 return _PutOnProgress(_ProgressHandler); 7378 } 7379 7380 virtual STDMETHODIMP Cancel() 7381 { 7382 if (_TransitionToState(_AsyncCancelPending)) 7383 { 7384 _OnCancel(); 7385 } 7386 return S_OK; 7387 } 7388 7389 virtual STDMETHODIMP Close() 7390 { 7391 if (_TransitionToState(_AsyncClosed)) 7392 { 7393 _OnClose(); 7394 } 7395 else 7396 { 7397 if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored 7398 { 7399 return E_ILLEGAL_STATE_CHANGE; 7400 } 7401 } 7402 return S_OK; 7403 } 7404 7405 virtual STDMETHODIMP get_Completed(typename _Attributes::_CompletionDelegateType** _CompleteHandler) 7406 { 7407 _CheckValidStateForDelegateCall(); 7408 if (!_CompleteHandler) return E_POINTER; 7409 *_CompleteHandler = _M_completeDelegate.Get(); 7410 return S_OK; 7411 } 7412 7413 virtual STDMETHODIMP put_Completed(typename _Attributes::_CompletionDelegateType* _CompleteHandler) 7414 { 7415 _CheckValidStateForDelegateCall(); 7416 // this delegate property is "write once" 7417 if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1) 7418 { 7419 _M_completeDelegateContext = _ContextCallback::_CaptureCurrent(); 7420 _M_completeDelegate = _CompleteHandler; 7421 // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below 7422 // as perceived from _FireCompletion on another thread. 7423 MemoryBarrier(); 7424 if (_IsTerminalState()) 7425 { 7426 _FireCompletion(); 7427 } 7428 } 7429 else 7430 { 7431 return E_ILLEGAL_DELEGATE_ASSIGNMENT; 7432 } 7433 return S_OK; 7434 } 7435 7436 protected: 7437 // _Start - this is not externally visible since async operations "hot start" before returning to the caller 7438 STDMETHODIMP _Start() 7439 { 7440 if (_TransitionToState(_AsyncStarted)) 7441 { 7442 _OnStart(); 7443 } 7444 else 7445 { 7446 return E_ILLEGAL_STATE_CHANGE; 7447 } 7448 return S_OK; 7449 } 7450 7451 HRESULT _FireCompletion() 7452 { 7453 HRESULT hr = S_OK; 7454 _TryTransitionToCompleted(); 7455 7456 // we guarantee that completion can only ever be fired once 7457 if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1) 7458 { 7459 hr = _M_completeDelegateContext._CallInContext([=]() -> HRESULT { 7460 ABI::Windows::Foundation::AsyncStatus status; 7461 HRESULT hr; 7462 if (SUCCEEDED(hr = this->get_Status(&status))) 7463 _M_completeDelegate->Invoke((_Attributes::_AsyncBaseType*)this, status); 7464 _M_completeDelegate = nullptr; 7465 return hr; 7466 }); 7467 } 7468 return hr; 7469 } 7470 7471 virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) 7472 { 7473 (void)_ProgressHandler; 7474 return E_UNEXPECTED; 7475 } 7476 7477 virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) 7478 { 7479 (void)_ProgressHandler; 7480 return E_UNEXPECTED; 7481 } 7482 7483 7484 bool _TryTransitionToCompleted() 7485 { 7486 return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted); 7487 } 7488 7489 bool _TryTransitionToCancelled() 7490 { 7491 return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled); 7492 } 7493 7494 bool _TryTransitionToError(const HRESULT error) 7495 { 7496 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK); 7497 return _TransitionToState(_AsyncStatusInternal::_AsyncError); 7498 } 7499 7500 // This method checks to see if the delegate properties can be 7501 // modified in the current state and generates the appropriate 7502 // error hr in the case of violation. 7503 inline HRESULT _CheckValidStateForDelegateCall() 7504 { 7505 if (_M_currentStatus == _AsyncClosed) 7506 { 7507 return E_ILLEGAL_METHOD_CALL; 7508 } 7509 return S_OK; 7510 } 7511 7512 // This method checks to see if results can be collected in the 7513 // current state and generates the appropriate error hr in 7514 // the case of a violation. 7515 inline HRESULT _CheckValidStateForResultsCall() 7516 { 7517 _AsyncStatusInternal _Current = _M_currentStatus; 7518 7519 if (_Current == _AsyncError) 7520 { 7521 return _M_errorCode; 7522 } 7523 #pragma warning(push) 7524 #pragma warning(disable: 4127) // Conditional expression is constant 7525 // single result illegal before transition to Completed or Cancelled state 7526 if (resultType == SingleResult) 7527 #pragma warning(pop) 7528 { 7529 if (_Current != _AsyncCompleted) 7530 { 7531 return E_ILLEGAL_METHOD_CALL; 7532 } 7533 } 7534 // multiple results can be called after Start has been called and before/after Completed 7535 else if (_Current != _AsyncStarted && 7536 _Current != _AsyncCancelPending && 7537 _Current != _AsyncCanceled && 7538 _Current != _AsyncCompleted) 7539 { 7540 return E_ILLEGAL_METHOD_CALL; 7541 } 7542 return S_OK; 7543 } 7544 7545 // This method can be called by derived classes periodically to determine 7546 // whether the asynchronous operation should continue processing or should 7547 // be halted. 7548 inline bool _ContinueAsyncOperation() 7549 { 7550 return _M_currentStatus == _AsyncStarted; 7551 } 7552 7553 // These two methods are used to allow the async worker implementation do work on 7554 // state transitions. No real "work" should be done in these methods. In other words 7555 // they should not block for a long time on UI timescales. 7556 virtual void _OnStart() = 0; 7557 virtual void _OnClose() = 0; 7558 virtual void _OnCancel() = 0; 7559 7560 private: 7561 7562 // This method is used to check if calls to the AsyncInfo properties 7563 // (id, status, errorcode) are legal in the current state. It also 7564 // generates the appropriate error hr to return in the case of an 7565 // illegal call. 7566 inline HRESULT _CheckValidStateForAsyncInfoCall() 7567 { 7568 _AsyncStatusInternal _Current = _M_currentStatus; 7569 if (_Current == _AsyncClosed) 7570 { 7571 return E_ILLEGAL_METHOD_CALL; 7572 } 7573 else if (_Current == _AsyncCreated) 7574 { 7575 return E_ASYNC_OPERATION_NOT_STARTED; 7576 } 7577 return S_OK; 7578 } 7579 7580 inline bool _TransitionToState(const _AsyncStatusInternal _NewState) 7581 { 7582 _AsyncStatusInternal _Current = _M_currentStatus; 7583 7584 // This enforces the valid state transitions of the asynchronous worker object 7585 // state machine. 7586 switch (_NewState) 7587 { 7588 case _AsyncStatusInternal::_AsyncStarted: 7589 if (_Current != _AsyncCreated) 7590 { 7591 return false; 7592 } 7593 break; 7594 case _AsyncStatusInternal::_AsyncCompleted: 7595 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending) 7596 { 7597 return false; 7598 } 7599 break; 7600 case _AsyncStatusInternal::_AsyncCancelPending: 7601 if (_Current != _AsyncStarted) 7602 { 7603 return false; 7604 } 7605 break; 7606 case _AsyncStatusInternal::_AsyncCanceled: 7607 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending) 7608 { 7609 return false; 7610 } 7611 break; 7612 case _AsyncStatusInternal::_AsyncError: 7613 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending) 7614 { 7615 return false; 7616 } 7617 break; 7618 case _AsyncStatusInternal::_AsyncClosed: 7619 if (!_IsTerminalState(_Current)) 7620 { 7621 return false; 7622 } 7623 break; 7624 default: 7625 return false; 7626 break; 7627 } 7628 7629 // attempt the transition to the new state 7630 // Note: if currentStatus_ == _Current, then there was no intervening write 7631 // by the async work object and the swap succeeded. 7632 _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>( 7633 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus), 7634 _NewState, 7635 static_cast<LONG>(_Current))); 7636 7637 // ICE returns the former state, if the returned state and the 7638 // state we captured at the beginning of this method are the same, 7639 // the swap succeeded. 7640 return (_RetState == _Current); 7641 } 7642 7643 inline bool _IsTerminalState() 7644 { 7645 return _IsTerminalState(_M_currentStatus); 7646 } 7647 7648 inline bool _IsTerminalState(_AsyncStatusInternal status) 7649 { 7650 return (status == _AsyncError || 7651 status == _AsyncCanceled || 7652 status == _AsyncCompleted || 7653 status == _AsyncClosed); 7654 } 7655 7656 private: 7657 7658 _ContextCallback _M_completeDelegateContext; 7659 Microsoft::WRL::ComPtr<typename _Attributes::_CompletionDelegateType> _M_completeDelegate; //ComPtr cannot be volatile as it does not have volatile accessors 7660 _AsyncStatusInternal volatile _M_currentStatus; 7661 HRESULT volatile _M_errorCode; 7662 unsigned int _M_id; 7663 long volatile _M_CompleteDelegateAssigned; 7664 long volatile _M_CallbackMade; 7665 }; 7666 7667 // *************************************************************************** 7668 // Progress Layer (optional): 7669 // 7670 7671 template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult > 7672 class _AsyncProgressBase abstract : public _AsyncInfoBase<_Attributes, _ResultType> 7673 { 7674 }; 7675 7676 template< typename _Attributes, _AsyncResultType _ResultType> 7677 class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : public _AsyncInfoBase<_Attributes, _ResultType> 7678 { 7679 public: 7680 7681 _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(), 7682 _M_progressDelegate(nullptr) 7683 { 7684 } 7685 7686 virtual STDMETHODIMP _GetOnProgress(typename _Attributes::_ProgressDelegateType** _ProgressHandler) override 7687 { 7688 HRESULT hr = _CheckValidStateForDelegateCall(); 7689 if (FAILED(hr)) return hr; 7690 *_ProgressHandler = _M_progressDelegate; 7691 return S_OK; 7692 } 7693 7694 virtual STDMETHODIMP _PutOnProgress(typename _Attributes::_ProgressDelegateType* _ProgressHandler) override 7695 { 7696 HRESULT hr = _CheckValidStateForDelegateCall(); 7697 if (FAILED(hr)) return hr; 7698 _M_progressDelegate = _ProgressHandler; 7699 _M_progressDelegateContext = _ContextCallback::_CaptureCurrent(); 7700 return S_OK; 7701 } 7702 7703 public: 7704 7705 void _FireProgress(const typename _Attributes::_ProgressType_abi& _ProgressValue) 7706 { 7707 if (_M_progressDelegate != nullptr) 7708 { 7709 _M_progressDelegateContext._CallInContext([=]() -> HRESULT { 7710 _M_progressDelegate->Invoke((_Attributes::_AsyncBaseType*)this, _ProgressValue); 7711 return S_OK; 7712 }); 7713 } 7714 } 7715 7716 private: 7717 7718 _ContextCallback _M_progressDelegateContext; 7719 typename _Attributes::_ProgressDelegateType* _M_progressDelegate; 7720 }; 7721 7722 template<typename _Attributes, _AsyncResultType _ResultType = SingleResult> 7723 class _AsyncBaseProgressLayer abstract : public _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType> 7724 { 7725 }; 7726 7727 // *************************************************************************** 7728 // Task Adaptation Layer: 7729 // 7730 7731 // 7732 // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task. 7733 // 7734 template<typename _Attributes, typename _ReturnType> 7735 class _AsyncTaskThunkBase abstract : public _AsyncBaseProgressLayer<_Attributes> 7736 { 7737 public: 7738 7739 //AsyncAction* 7740 virtual STDMETHODIMP GetResults() 7741 { 7742 HRESULT hr = _CheckValidStateForResultsCall(); 7743 if (FAILED(hr)) return hr; 7744 _M_task.get(); 7745 return S_OK; 7746 } 7747 public: 7748 typedef task<_ReturnType> _TaskType; 7749 7750 _AsyncTaskThunkBase(const _TaskType& _Task) 7751 : _M_task(_Task) 7752 { 7753 } 7754 7755 _AsyncTaskThunkBase() 7756 { 7757 } 7758 #if _MSC_VER < 1800 7759 void _SetTaskCreationAddressHint(void* _SourceAddressHint) 7760 { 7761 if (!(std::is_same<_Attributes::_AsyncKind, _TypeSelectorAsyncTask>::value)) 7762 { 7763 // Overwrite the creation address with the return address of create_async unless the 7764 // lambda returned a task. If the create async lambda returns a task, that task is reused and 7765 // we want to preserve its creation address hint. 7766 _M_task._SetTaskCreationAddressHint(_SourceAddressHint); 7767 } 7768 } 7769 #endif 7770 protected: 7771 virtual void _OnStart() override 7772 { 7773 _M_task.then([=](_TaskType _Antecedent) -> HRESULT { 7774 try 7775 { 7776 _Antecedent.get(); 7777 } 7778 catch (Concurrency::task_canceled&) 7779 { 7780 _TryTransitionToCancelled(); 7781 } 7782 catch (IRestrictedErrorInfo*& _Ex) 7783 { 7784 HRESULT hr; 7785 HRESULT _hr; 7786 hr = _Ex->GetErrorDetails(NULL, &_hr, NULL, NULL); 7787 if (SUCCEEDED(hr)) hr = _hr; 7788 _TryTransitionToError(hr); 7789 } 7790 catch (...) 7791 { 7792 _TryTransitionToError(E_FAIL); 7793 } 7794 return _FireCompletion(); 7795 }); 7796 } 7797 7798 protected: 7799 _TaskType _M_task; 7800 Concurrency::cancellation_token_source _M_cts; 7801 }; 7802 7803 template<typename _Attributes, typename _ReturnType, typename _Return> 7804 class _AsyncTaskReturn abstract : public _AsyncTaskThunkBase<_Attributes, _Return> 7805 { 7806 public: 7807 //AsyncOperation* 7808 virtual STDMETHODIMP GetResults(_ReturnType* results) 7809 { 7810 HRESULT hr = _CheckValidStateForResultsCall(); 7811 if (FAILED(hr)) return hr; 7812 _M_task.get(); 7813 *results = _M_results; 7814 return S_OK; 7815 } 7816 template <typename _Function> 7817 #if _MSC_VER >= 1800 7818 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack) 7819 { 7820 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results, _callstack); 7821 } 7822 #else 7823 void DoCreateTask(_Function _func) 7824 { 7825 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results); 7826 } 7827 #endif 7828 protected: 7829 _ReturnType _M_results; 7830 }; 7831 7832 template<typename _Attributes, typename _ReturnType> 7833 class _AsyncTaskReturn<_Attributes, _ReturnType, void> abstract : public _AsyncTaskThunkBase<_Attributes, void> 7834 { 7835 public: 7836 template <typename _Function> 7837 #if _MSC_VER >= 1800 7838 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack) 7839 { 7840 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, _callstack); 7841 } 7842 #else 7843 void DoCreateTask(_Function _func) 7844 { 7845 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts); 7846 } 7847 #endif 7848 }; 7849 7850 template<typename _Attributes> 7851 class _AsyncTaskReturn<_Attributes, void, task<void>> abstract : public _AsyncTaskThunkBase<_Attributes, task<void>> 7852 { 7853 public: 7854 template <typename _Function> 7855 #if _MSC_VER >= 1800 7856 void DoCreateTask(_Function _func, const _TaskCreationCallstack & _callstack) 7857 { 7858 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results, _callstack); 7859 } 7860 #else 7861 void DoCreateTask(_Function _func) 7862 { 7863 _M_task = _Attributes::_Generate_Task(_func, this, _M_cts, &_M_results); 7864 } 7865 #endif 7866 protected: 7867 task<void> _M_results; 7868 }; 7869 7870 template<typename _Attributes> 7871 class _AsyncTaskThunk : public _AsyncTaskReturn<_Attributes, typename _Attributes::_ReturnType_abi, typename _Attributes::_ReturnType> 7872 { 7873 public: 7874 7875 _AsyncTaskThunk(const _TaskType& _Task) : 7876 _AsyncTaskThunkBase(_Task) 7877 { 7878 } 7879 7880 _AsyncTaskThunk() 7881 { 7882 } 7883 7884 protected: 7885 7886 virtual void _OnClose() override 7887 { 7888 } 7889 7890 virtual void _OnCancel() override 7891 { 7892 _M_cts.cancel(); 7893 } 7894 }; 7895 7896 // *************************************************************************** 7897 // Async Creation Layer: 7898 // 7899 template<typename _Function> 7900 class _AsyncTaskGeneratorThunk : public _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes> 7901 { 7902 public: 7903 7904 typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes; 7905 typedef typename _AsyncTaskThunk<_Attributes> _Base; 7906 typedef typename _Attributes::_AsyncBaseType _AsyncBaseType; 7907 7908 #if _MSC_VER >= 1800 7909 _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack) 7910 #else 7911 _AsyncTaskGeneratorThunk(const _Function& _Func) : _M_func(_Func) 7912 #endif 7913 { 7914 // Virtual call here is safe as the class is declared 'sealed' 7915 _Start(); 7916 } 7917 7918 protected: 7919 7920 // 7921 // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise, 7922 // let the base thunk handle everything. 7923 // 7924 7925 virtual void _OnStart() override 7926 { 7927 // 7928 // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports, 7929 // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda. 7930 // 7931 #if _MSC_VER >= 1800 7932 DoCreateTask<_Function>(_M_func, _M_creationCallstack); 7933 #else 7934 DoCreateTask<_Function>(_M_func); 7935 #endif 7936 _Base::_OnStart(); 7937 } 7938 7939 virtual void _OnCancel() override 7940 { 7941 _Base::_OnCancel(); 7942 } 7943 7944 private: 7945 #if _MSC_VER >= 1800 7946 _TaskCreationCallstack _M_creationCallstack; 7947 #endif 7948 _Function _M_func; 7949 }; 7950 } // namespace details 7951 7952 /// <summary> 7953 /// Creates a Windows Runtime asynchronous construct based on a user supplied lambda or function object. The return type of <c>create_async</c> is 7954 /// one of either <c>IAsyncAction^</c>, <c>IAsyncActionWithProgress<TProgress>^</c>, <c>IAsyncOperation<TResult>^</c>, or 7955 /// <c>IAsyncOperationWithProgress<TResult, TProgress>^</c> based on the signature of the lambda passed to the method. 7956 /// </summary> 7957 /// <param name="_Func"> 7958 /// The lambda or function object from which to create a Windows Runtime asynchronous construct. 7959 /// </param> 7960 /// <returns> 7961 /// An asynchronous construct represented by an IAsyncAction^, IAsyncActionWithProgress<TProgress>^, IAsyncOperation<TResult>^, or an 7962 /// IAsyncOperationWithProgress<TResult, TProgress>^. The interface returned depends on the signature of the lambda passed into the function. 7963 /// </returns> 7964 /// <remarks> 7965 /// The return type of the lambda determines whether the construct is an action or an operation. 7966 /// <para>Lambdas that return void cause the creation of actions. Lambdas that return a result of type <c>TResult</c> cause the creation of 7967 /// operations of TResult.</para> 7968 /// <para>The lambda may also return a <c>task<TResult></c> which encapsulates the aysnchronous work within itself or is the continuation of 7969 /// a chain of tasks that represent the asynchronous work. In this case, the lambda itself is executed inline, since the tasks are the ones that 7970 /// execute asynchronously, and the return type of the lambda is unwrapped to produce the asynchronous construct returned by <c>create_async</c>. 7971 /// This implies that a lambda that returns a task<void> will cause the creation of actions, and a lambda that returns a task<TResult> will 7972 /// cause the creation of operations of TResult.</para> 7973 /// <para>The lambda may take either zero, one or two arguments. The valid arguments are <c>progress_reporter<TProgress></c> and 7974 /// <c>cancellation_token</c>, in that order if both are used. A lambda without arguments causes the creation of an asynchronous construct without 7975 /// the capability for progress reporting. A lambda that takes a progress_reporter<TProgress> will cause <c>create_async</c> to return an asynchronous 7976 /// construct which reports progress of type TProgress each time the <c>report</c> method of the progress_reporter object is called. A lambda that 7977 /// takes a cancellation_token may use that token to check for cancellation, or pass it to tasks that it creates so that cancellation of the 7978 /// asynchronous construct causes cancellation of those tasks.</para> 7979 /// <para>If the body of the lambda or function object returns a result (and not a task<TResult>), the lamdba will be executed 7980 /// asynchronously within the process MTA in the context of a task the Runtime implicitly creates for it. The <c>IAsyncInfo::Cancel</c> method will 7981 /// cause cancellation of the implicit task.</para> 7982 /// <para>If the body of the lambda returns a task, the lamba executes inline, and by declaring the lambda to take an argument of type 7983 /// <c>cancellation_token</c> you can trigger cancellation of any tasks you create within the lambda by passing that token in when you create them. 7984 /// You may also use the <c>register_callback</c> method on the token to cause the Runtime to invoke a callback when you call <c>IAsyncInfo::Cancel</c> on 7985 /// the async operation or action produced..</para> 7986 /// <para>This function is only available to Windows Store apps.</para> 7987 /// </remarks> 7988 /// <seealso cref="task Class"/> 7989 /// <seealso cref="progress_reporter Class"/> 7990 /// <seealso cref="cancelation_token Class"/> 7991 /**/ 7992 template<typename _ReturnType, typename _Function> 7993 __declspec(noinline) // Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result 7994 details::_AsyncTaskGeneratorThunk<_Function>* create_async(const _Function& _Func) 7995 { 7996 static_assert(std::is_same<decltype(details::_IsValidCreateAsync<_ReturnType>(_Func, 0, 0, 0, 0, 0, 0, 0, 0)), std::true_type>::value, 7997 "argument to create_async must be a callable object taking zero, one, two or three arguments"); 7998 #if _MSC_VER >= 1800 7999 Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func, _CAPTURE_CALLSTACK()); 8000 #else 8001 Microsoft::WRL::ComPtr<details::_AsyncTaskGeneratorThunk<_Function>> _AsyncInfo = Microsoft::WRL::Make<details::_AsyncTaskGeneratorThunk<_Function>>(_Func); 8002 _AsyncInfo->_SetTaskCreationAddressHint(_ReturnAddress()); 8003 #endif 8004 return _AsyncInfo.Detach(); 8005 } 8006 8007 namespace details 8008 { 8009 #if _MSC_VER < 1800 8010 // Internal API which retrieves the next async id. 8011 _CRTIMP2 unsigned int __cdecl _GetNextAsyncId(); 8012 #endif 8013 // Helper struct for when_all operators to know when tasks have completed 8014 template<typename _Type> 8015 struct _RunAllParam 8016 { 8017 _RunAllParam() : _M_completeCount(0), _M_numTasks(0) 8018 { 8019 } 8020 8021 void _Resize(size_t _Len, bool _SkipVector = false) 8022 { 8023 _M_numTasks = _Len; 8024 if (!_SkipVector) 8025 #if _MSC_VER >= 1800 8026 { 8027 _M_vector._Result.resize(_Len); 8028 } 8029 #else 8030 _M_vector.resize(_Len); 8031 _M_contexts.resize(_Len); 8032 #endif 8033 } 8034 8035 task_completion_event<_Unit_type> _M_completed; 8036 atomic_size_t _M_completeCount; 8037 #if _MSC_VER >= 1800 8038 _ResultHolder<std::vector<_Type> > _M_vector; 8039 _ResultHolder<_Type> _M_mergeVal; 8040 #else 8041 std::vector<_Type> _M_vector; 8042 std::vector<_ContextCallback> _M_contexts; 8043 _Type _M_mergeVal; 8044 #endif 8045 size_t _M_numTasks; 8046 }; 8047 8048 #if _MSC_VER >= 1800 8049 template<typename _Type> 8050 struct _RunAllParam<std::vector<_Type> > 8051 { 8052 _RunAllParam() : _M_completeCount(0), _M_numTasks(0) 8053 { 8054 } 8055 8056 void _Resize(size_t _Len, bool _SkipVector = false) 8057 { 8058 _M_numTasks = _Len; 8059 8060 if (!_SkipVector) 8061 { 8062 _M_vector.resize(_Len); 8063 } 8064 } 8065 8066 task_completion_event<_Unit_type> _M_completed; 8067 std::vector<_ResultHolder<std::vector<_Type> > > _M_vector; 8068 atomic_size_t _M_completeCount; 8069 size_t _M_numTasks; 8070 }; 8071 #endif 8072 8073 // Helper struct specialization for void 8074 template<> 8075 #if _MSC_VER >= 1800 8076 struct _RunAllParam<_Unit_type> 8077 #else 8078 struct _RunAllParam<void> 8079 #endif 8080 { 8081 _RunAllParam() : _M_completeCount(0), _M_numTasks(0) 8082 { 8083 } 8084 8085 void _Resize(size_t _Len) 8086 { 8087 _M_numTasks = _Len; 8088 } 8089 8090 task_completion_event<_Unit_type> _M_completed; 8091 atomic_size_t _M_completeCount; 8092 size_t _M_numTasks; 8093 }; 8094 8095 inline void _JoinAllTokens_Add(const Concurrency::cancellation_token_source& _MergedSrc, Concurrency::details::_CancellationTokenState *_PJoinedTokenState) 8096 { 8097 if (_PJoinedTokenState != nullptr && _PJoinedTokenState != Concurrency::details::_CancellationTokenState::_None()) 8098 { 8099 Concurrency::cancellation_token _T = Concurrency::cancellation_token::_FromImpl(_PJoinedTokenState); 8100 _T.register_callback([=](){ 8101 _MergedSrc.cancel(); 8102 }); 8103 } 8104 } 8105 8106 template<typename _ElementType, typename _Function, typename _TaskType> 8107 void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task) 8108 { 8109 if (_Task._GetImpl()->_IsCompleted()) 8110 { 8111 _Func(); 8112 #if _MSC_VER >= 1800 8113 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) 8114 #else 8115 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks) 8116 #endif 8117 { 8118 // Inline execute its direct continuation, the _ReturnTask 8119 _PParam->_M_completed.set(_Unit_type()); 8120 // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished. 8121 delete _PParam; 8122 } 8123 } 8124 else 8125 { 8126 _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled()); 8127 if (_Task._GetImpl()->_HasUserException()) 8128 { 8129 // _Cancel will return false if the TCE is already canceled with or without exception 8130 _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder()); 8131 } 8132 else 8133 { 8134 _PParam->_M_completed._Cancel(); 8135 } 8136 #if _MSC_VER >= 1800 8137 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) 8138 #else 8139 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks) 8140 #endif 8141 { 8142 delete _PParam; 8143 } 8144 } 8145 } 8146 8147 template<typename _ElementType, typename _Iterator> 8148 struct _WhenAllImpl 8149 { 8150 #if _MSC_VER >= 1800 8151 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) 8152 #else 8153 static task<std::vector<_ElementType>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End) 8154 #endif 8155 { 8156 #if _MSC_VER >= 1800 8157 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 8158 #endif 8159 auto _PParam = new _RunAllParam<_ElementType>(); 8160 Concurrency::cancellation_token_source _MergedSource; 8161 8162 // Step1: Create task completion event. 8163 #if _MSC_VER >= 1800 8164 task_options _Options(_TaskOptions); 8165 _Options.set_cancellation_token(_MergedSource.get_token()); 8166 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); 8167 #else 8168 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token()); 8169 #endif 8170 // The return task must be created before step 3 to enforce inline execution. 8171 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ElementType>* retVal) -> HRESULT { 8172 #if _MSC_VER >= 1800 8173 * retVal = _PParam->_M_vector.Get(); 8174 #else 8175 auto _Result = _PParam->_M_vector; // copy by value 8176 8177 size_t _Index = 0; 8178 for (auto _It = _Result.begin(); _It != _Result.end(); ++_It) 8179 { 8180 *_It = _ResultContext<_ElementType>::_GetValue(*_It, _PParam->_M_contexts[_Index++], false); 8181 } 8182 *retVal = _Result; 8183 #endif 8184 return S_OK; 8185 #if _MSC_VER >= 1800 8186 }, nullptr); 8187 #else 8188 }, nullptr, true); 8189 #endif 8190 // Step2: Combine and check tokens, and count elements in range. 8191 if (_PTokenState) 8192 { 8193 details::_JoinAllTokens_Add(_MergedSource, _PTokenState); 8194 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End))); 8195 } 8196 else 8197 { 8198 size_t _TaskNum = 0; 8199 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8200 { 8201 _TaskNum++; 8202 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState); 8203 } 8204 _PParam->_Resize(_TaskNum); 8205 } 8206 8207 // Step3: Check states of previous tasks. 8208 if (_Begin == _End) 8209 { 8210 _PParam->_M_completed.set(_Unit_type()); 8211 delete _PParam; 8212 } 8213 else 8214 { 8215 size_t _Index = 0; 8216 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8217 { 8218 if (_PTask->is_apartment_aware()) 8219 { 8220 _ReturnTask._SetAsync(); 8221 } 8222 8223 _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) -> HRESULT { 8224 8225 #if _MSC_VER >= 1800 8226 // Dev10 compiler bug 8227 typedef _ElementType _ElementTypeDev10; 8228 auto _PParamCopy = _PParam; 8229 auto _IndexCopy = _Index; 8230 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){ 8231 _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult(); 8232 }; 8233 #else 8234 auto _Func = [_PParam, _Index, &_ResultTask](){ 8235 _PParam->_M_vector[_Index] = _ResultTask._GetImpl()->_GetResult(); 8236 _PParam->_M_contexts[_Index] = _ResultContext<_ElementType>::_GetContext(false); 8237 }; 8238 #endif 8239 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); 8240 return S_OK; 8241 #if _MSC_VER >= 1800 8242 }, Concurrency::details::_CancellationTokenState::_None()); 8243 #else 8244 }, Concurrency::details::_CancellationTokenState::_None(), false); 8245 #endif 8246 8247 _Index++; 8248 } 8249 } 8250 8251 return _ReturnTask; 8252 } 8253 }; 8254 8255 template<typename _ElementType, typename _Iterator> 8256 struct _WhenAllImpl<std::vector<_ElementType>, _Iterator> 8257 { 8258 #if _MSC_VER >= 1800 8259 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) 8260 #else 8261 static task<std::vector<_ElementType>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End) 8262 #endif 8263 { 8264 #if _MSC_VER >= 1800 8265 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 8266 #endif 8267 auto _PParam = new _RunAllParam<std::vector<_ElementType>>(); 8268 Concurrency::cancellation_token_source _MergedSource; 8269 8270 // Step1: Create task completion event. 8271 #if _MSC_VER >= 1800 8272 task_options _Options(_TaskOptions); 8273 _Options.set_cancellation_token(_MergedSource.get_token()); 8274 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); 8275 #else 8276 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token()); 8277 #endif 8278 // The return task must be created before step 3 to enforce inline execution. 8279 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ElementType>* retVal) -> HRESULT { 8280 _CONCRT_ASSERT(_PParam->_M_completeCount == _PParam->_M_numTasks); 8281 std::vector<_ElementType> _Result; 8282 for (size_t _I = 0; _I < _PParam->_M_numTasks; _I++) 8283 { 8284 #if _MSC_VER >= 1800 8285 const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get(); 8286 #else 8287 std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I]; 8288 8289 for (auto _It = _Vec.begin(); _It != _Vec.end(); ++_It) 8290 { 8291 *_It = _ResultContext<_ElementType>::_GetValue(*_It, _PParam->_M_contexts[_I], false); 8292 } 8293 #endif 8294 _Result.insert(_Result.end(), _Vec.begin(), _Vec.end()); 8295 } 8296 *retVal = _Result; 8297 return S_OK; 8298 #if _MSC_VER >= 1800 8299 }, nullptr); 8300 #else 8301 }, nullptr, true); 8302 #endif 8303 8304 // Step2: Combine and check tokens, and count elements in range. 8305 if (_PTokenState) 8306 { 8307 details::_JoinAllTokens_Add(_MergedSource, _PTokenState); 8308 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End))); 8309 } 8310 else 8311 { 8312 size_t _TaskNum = 0; 8313 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8314 { 8315 _TaskNum++; 8316 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState); 8317 } 8318 _PParam->_Resize(_TaskNum); 8319 } 8320 8321 // Step3: Check states of previous tasks. 8322 if (_Begin == _End) 8323 { 8324 _PParam->_M_completed.set(_Unit_type()); 8325 delete _PParam; 8326 } 8327 else 8328 { 8329 size_t _Index = 0; 8330 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8331 { 8332 if (_PTask->is_apartment_aware()) 8333 { 8334 _ReturnTask._SetAsync(); 8335 } 8336 8337 _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) -> HRESULT { 8338 #if _MSC_VER >= 1800 8339 // Dev10 compiler bug 8340 typedef _ElementType _ElementTypeDev10; 8341 auto _PParamCopy = _PParam; 8342 auto _IndexCopy = _Index; 8343 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() { 8344 _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult()); 8345 }; 8346 #else 8347 auto _Func = [_PParam, _Index, &_ResultTask]() { 8348 _PParam->_M_vector[_Index] = _ResultTask._GetImpl()->_GetResult(); 8349 _PParam->_M_contexts[_Index] = _ResultContext<_ElementType>::_GetContext(false); 8350 }; 8351 #endif 8352 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); 8353 return S_OK; 8354 #if _MSC_VER >= 1800 8355 }, Concurrency::details::_CancellationTokenState::_None()); 8356 #else 8357 }, Concurrency::details::_CancellationTokenState::_None(), false); 8358 #endif 8359 8360 _Index++; 8361 } 8362 } 8363 8364 return _ReturnTask; 8365 } 8366 }; 8367 8368 template<typename _Iterator> 8369 struct _WhenAllImpl<void, _Iterator> 8370 { 8371 #if _MSC_VER >= 1800 8372 static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) 8373 #else 8374 static task<void> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End) 8375 #endif 8376 { 8377 #if _MSC_VER >= 1800 8378 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 8379 #endif 8380 auto _PParam = new _RunAllParam<_Unit_type>(); 8381 Concurrency::cancellation_token_source _MergedSource; 8382 8383 // Step1: Create task completion event. 8384 #if _MSC_VER >= 1800 8385 task_options _Options(_TaskOptions); 8386 _Options.set_cancellation_token(_MergedSource.get_token()); 8387 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options); 8388 #else 8389 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token()); 8390 #endif 8391 // The return task must be created before step 3 to enforce inline execution. 8392 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> HRESULT { return S_OK; 8393 #if _MSC_VER >= 1800 8394 }, nullptr); 8395 #else 8396 }, nullptr, false); 8397 #endif 8398 8399 // Step2: Combine and check tokens, and count elements in range. 8400 if (_PTokenState) 8401 { 8402 details::_JoinAllTokens_Add(_MergedSource, _PTokenState); 8403 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End))); 8404 } 8405 else 8406 { 8407 size_t _TaskNum = 0; 8408 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8409 { 8410 _TaskNum++; 8411 details::_JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState); 8412 } 8413 _PParam->_Resize(_TaskNum); 8414 } 8415 8416 // Step3: Check states of previous tasks. 8417 if (_Begin == _End) 8418 { 8419 _PParam->_M_completed.set(_Unit_type()); 8420 delete _PParam; 8421 } 8422 else 8423 { 8424 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8425 { 8426 if (_PTask->is_apartment_aware()) 8427 { 8428 _ReturnTask._SetAsync(); 8429 } 8430 8431 _PTask->_Then([_PParam](task<void> _ResultTask) -> HRESULT { 8432 8433 auto _Func = []() -> HRESULT { return S_OK; }; 8434 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); 8435 return S_OK; 8436 #if _MSC_VER >= 1800 8437 }, Concurrency::details::_CancellationTokenState::_None()); 8438 #else 8439 }, Concurrency::details::_CancellationTokenState::_None(), false); 8440 #endif 8441 } 8442 } 8443 8444 return _ReturnTask; 8445 } 8446 }; 8447 8448 template<typename _ReturnType> 8449 task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask, 8450 bool _OutputVectorFirst) 8451 { 8452 auto _PParam = new _RunAllParam<_ReturnType>(); 8453 Concurrency::cancellation_token_source _MergedSource; 8454 8455 // Step1: Create task completion event. 8456 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token()); 8457 // The return task must be created before step 3 to enforce inline execution. 8458 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type, std::vector<_ReturnType>* retVal) -> HRESULT { 8459 _CONCRT_ASSERT(_PParam->_M_completeCount == 2); 8460 #if _MSC_VER >= 1800 8461 auto _Result = _PParam->_M_vector.Get(); // copy by value 8462 auto _mergeVal = _PParam->_M_mergeVal.Get(); 8463 #else 8464 auto _Result = _PParam->_M_vector; // copy by value 8465 for (auto _It = _Result.begin(); _It != _Result.end(); ++_It) 8466 { 8467 *_It = _ResultContext<_ReturnType>::_GetValue(*_It, _PParam->_M_contexts[0], false); 8468 } 8469 #endif 8470 8471 if (_OutputVectorFirst == true) 8472 { 8473 #if _MSC_VER >= 1800 8474 _Result.push_back(_mergeVal); 8475 #else 8476 _Result.push_back(_ResultContext<_ReturnType>::_GetValue(_PParam->_M_mergeVal, _PParam->_M_contexts[1], false)); 8477 #endif 8478 } 8479 else 8480 { 8481 #if _MSC_VER >= 1800 8482 _Result.insert(_Result.begin(), _mergeVal); 8483 #else 8484 _Result.insert(_Result.begin(), _ResultContext<_ReturnType>::_GetValue(_PParam->_M_mergeVal, _PParam->_M_contexts[1], false)); 8485 #endif 8486 } 8487 *retVal = _Result; 8488 return S_OK; 8489 }, nullptr, true); 8490 8491 // Step2: Combine and check tokens. 8492 _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState); 8493 _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState); 8494 8495 // Step3: Check states of previous tasks. 8496 _PParam->_Resize(2, true); 8497 8498 if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware()) 8499 { 8500 _ReturnTask._SetAsync(); 8501 } 8502 _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) -> HRESULT { 8503 #if _MSC_VER >= 1800 8504 // Dev10 compiler bug 8505 typedef _ReturnType _ReturnTypeDev10; 8506 auto _PParamCopy = _PParam; 8507 auto _Func = [_PParamCopy, &_ResultTask]() { 8508 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); 8509 _PParamCopy->_M_vector.Set(_ResultLocal); 8510 }; 8511 #else 8512 auto _Func = [_PParam, &_ResultTask]() { 8513 _PParam->_M_vector = _ResultTask._GetImpl()->_GetResult(); 8514 _PParam->_M_contexts[0] = _ResultContext<_ReturnType>::_GetContext(false); 8515 }; 8516 #endif 8517 8518 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); 8519 return S_OK; 8520 #if _MSC_VER >= 1800 8521 }, _CancellationTokenState::_None()); 8522 #else 8523 }, _CancellationTokenState::_None(), false); 8524 #endif 8525 _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) -> HRESULT { 8526 #if _MSC_VER >= 1800 8527 // Dev10 compiler bug 8528 typedef _ReturnType _ReturnTypeDev10; 8529 auto _PParamCopy = _PParam; 8530 auto _Func = [_PParamCopy, &_ResultTask]() { 8531 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult(); 8532 _PParamCopy->_M_mergeVal.Set(_ResultLocal); 8533 }; 8534 #else 8535 auto _Func = [_PParam, &_ResultTask]() { 8536 _PParam->_M_mergeVal = _ResultTask._GetImpl()->_GetResult(); 8537 _PParam->_M_contexts[1] = _ResultContext<_ReturnType>::_GetContext(false); 8538 }; 8539 #endif 8540 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask); 8541 return S_OK; 8542 #if _MSC_VER >= 1800 8543 }, _CancellationTokenState::_None()); 8544 #else 8545 }, _CancellationTokenState::_None(), false); 8546 #endif 8547 8548 return _ReturnTask; 8549 } 8550 } // namespace details 8551 8552 #if _MSC_VER < 1800 8553 /// <summary> 8554 /// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully. 8555 /// </summary> 8556 /// <typeparam name="_Iterator"> 8557 /// The type of the input iterator. 8558 /// </typeparam> 8559 /// <param name="_Begin"> 8560 /// The position of the first element in the range of elements to be combined into the resulting task. 8561 /// </param> 8562 /// <param name="_End"> 8563 /// The position of the first element beyond the range of elements to be combined into the resulting task. 8564 /// </param> 8565 /// <returns> 8566 /// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8567 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8568 /// task will also be a <c>task<void></c>. 8569 /// </returns> 8570 /// <remarks> 8571 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8572 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8573 /// </remarks> 8574 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8575 /**/ 8576 template <typename _Iterator> 8577 auto when_all(_Iterator _Begin, _Iterator _End) 8578 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(nullptr, _Begin, _End)) 8579 { 8580 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 8581 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(nullptr, _Begin, _End); 8582 } 8583 #endif 8584 8585 /// <summary> 8586 /// Creates a task that will complete successfully when all of the tasks supplied as arguments complete successfully. 8587 /// </summary> 8588 /// <typeparam name="_Iterator"> 8589 /// The type of the input iterator. 8590 /// </typeparam> 8591 /// <param name="_Begin"> 8592 /// The position of the first element in the range of elements to be combined into the resulting task. 8593 /// </param> 8594 /// <param name="_End"> 8595 /// The position of the first element beyond the range of elements to be combined into the resulting task. 8596 /// </param> 8597 /// <param name="_CancellationToken"> 8598 /// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting 8599 /// task will be created with a token that is a combination of all the cancelable tokens (tokens created by methods other than 8600 /// <c>cancellation_token::none()</c>of the tasks supplied. 8601 /// </param> 8602 /// <returns> 8603 /// A task that completes sucessfully when all of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8604 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8605 /// task will also be a <c>task<void></c>. 8606 /// </returns> 8607 /// <remarks> 8608 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8609 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8610 /// </remarks> 8611 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8612 /**/ 8613 template <typename _Iterator> 8614 #if _MSC_VER >= 1800 8615 auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) 8616 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End)) 8617 { 8618 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 8619 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End); 8620 } 8621 #else 8622 auto when_all(_Iterator _Begin, _Iterator _End, Concurrency::cancellation_token _CancellationToken) 8623 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End)) 8624 { 8625 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 8626 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End); 8627 } 8628 #endif 8629 8630 /// <summary> 8631 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. 8632 /// </summary> 8633 /// <typeparam name="_ReturnType"> 8634 /// The type of the returned task. 8635 /// </typeparam> 8636 /// <param name="_Lhs"> 8637 /// The first task to combine into the resulting task. 8638 /// </param> 8639 /// <param name="_Rhs"> 8640 /// The second task to combine into the resulting task. 8641 /// </param> 8642 /// <returns> 8643 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8644 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8645 /// task will also be a <c>task<void></c>. 8646 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator 8647 /// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para> 8648 /// </returns> 8649 /// <remarks> 8650 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8651 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8652 /// </remarks> 8653 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8654 /**/ 8655 template<typename _ReturnType> 8656 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) 8657 { 8658 task<_ReturnType> _PTasks[2] = { _Lhs, _Rhs }; 8659 return when_all(_PTasks, _PTasks + 2); 8660 } 8661 8662 /// <summary> 8663 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. 8664 /// </summary> 8665 /// <typeparam name="_ReturnType"> 8666 /// The type of the returned task. 8667 /// </typeparam> 8668 /// <param name="_Lhs"> 8669 /// The first task to combine into the resulting task. 8670 /// </param> 8671 /// <param name="_Rhs"> 8672 /// The second task to combine into the resulting task. 8673 /// </param> 8674 /// <returns> 8675 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8676 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8677 /// task will also be a <c>task<void></c>. 8678 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator 8679 /// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para> 8680 /// </returns> 8681 /// <remarks> 8682 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8683 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8684 /// </remarks> 8685 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8686 /**/ 8687 template<typename _ReturnType> 8688 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs) 8689 { 8690 return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true); 8691 } 8692 8693 /// <summary> 8694 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. 8695 /// </summary> 8696 /// <typeparam name="_ReturnType"> 8697 /// The type of the returned task. 8698 /// </typeparam> 8699 /// <param name="_Lhs"> 8700 /// The first task to combine into the resulting task. 8701 /// </param> 8702 /// <param name="_Rhs"> 8703 /// The second task to combine into the resulting task. 8704 /// </param> 8705 /// <returns> 8706 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8707 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8708 /// task will also be a <c>task<void></c>. 8709 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator 8710 /// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para> 8711 /// </returns> 8712 /// <remarks> 8713 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8714 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8715 /// </remarks> 8716 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8717 /**/ 8718 template<typename _ReturnType> 8719 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs) 8720 { 8721 return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false); 8722 } 8723 8724 /// <summary> 8725 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. 8726 /// </summary> 8727 /// <typeparam name="_ReturnType"> 8728 /// The type of the returned task. 8729 /// </typeparam> 8730 /// <param name="_Lhs"> 8731 /// The first task to combine into the resulting task. 8732 /// </param> 8733 /// <param name="_Rhs"> 8734 /// The second task to combine into the resulting task. 8735 /// </param> 8736 /// <returns> 8737 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8738 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8739 /// task will also be a <c>task<void></c>. 8740 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator 8741 /// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para> 8742 /// </returns> 8743 /// <remarks> 8744 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8745 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8746 /// </remarks> 8747 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8748 /**/ 8749 template<typename _ReturnType> 8750 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs) 8751 { 8752 task<std::vector<_ReturnType>> _PTasks[2] = { _Lhs, _Rhs }; 8753 return when_all(_PTasks, _PTasks + 2); 8754 } 8755 8756 /// <summary> 8757 /// Creates a task that will complete successfully when both of the tasks supplied as arguments complete successfully. 8758 /// </summary> 8759 /// <typeparam name="_ReturnType"> 8760 /// The type of the returned task. 8761 /// </typeparam> 8762 /// <param name="_Lhs"> 8763 /// The first task to combine into the resulting task. 8764 /// </param> 8765 /// <param name="_Rhs"> 8766 /// The second task to combine into the resulting task. 8767 /// </param> 8768 /// <returns> 8769 /// A task that completes successfully when both of the input tasks have completed successfully. If the input tasks are of type <c>T</c>, 8770 /// the output of this function will be a <c>task<std::vector<T>></c>. If the input tasks are of type <c>void</c> the output 8771 /// task will also be a <c>task<void></c>. 8772 /// <para> To allow for a construct of the sort taskA && taskB && taskC, which are combined in pairs, the && operator 8773 /// produces a <c>task<std::vector<T>></c> if either one or both of the tasks are of type <c>task<std::vector<T>></c>.</para> 8774 /// </returns> 8775 /// <remarks> 8776 /// If one of the tasks is canceled or throws an exception, the returned task will complete early, in the canceled state, and the exception, 8777 /// if one is encoutered, will be thrown if you call <c>get()</c> or <c>wait()</c> on that task. 8778 /// </remarks> 8779 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 8780 /**/ 8781 inline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs) 8782 { 8783 task<void> _PTasks[2] = { _Lhs, _Rhs }; 8784 return when_all(_PTasks, _PTasks + 2); 8785 } 8786 8787 namespace details 8788 { 8789 // Helper struct for when_any operators to know when tasks have completed 8790 template <typename _CompletionType> 8791 struct _RunAnyParam 8792 { 8793 _RunAnyParam() : _M_completeCount(0), _M_numTasks(0), _M_exceptionRelatedToken(nullptr), _M_fHasExplicitToken(false) 8794 { 8795 } 8796 ~_RunAnyParam() 8797 { 8798 if (Concurrency::details::_CancellationTokenState::_IsValid(_M_exceptionRelatedToken)) 8799 _M_exceptionRelatedToken->_Release(); 8800 } 8801 task_completion_event<_CompletionType> _M_Completed; 8802 Concurrency::cancellation_token_source _M_cancellationSource; 8803 Concurrency::details::_CancellationTokenState* _M_exceptionRelatedToken; 8804 atomic_size_t _M_completeCount; 8805 size_t _M_numTasks; 8806 bool _M_fHasExplicitToken; 8807 }; 8808 8809 template<typename _CompletionType, typename _Function, typename _TaskType> 8810 void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task) 8811 { 8812 bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != Concurrency::details::_CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled(); 8813 if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled) 8814 { 8815 _Func(); 8816 #if _MSC_VER >= 1800 8817 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) 8818 #else 8819 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks) 8820 #endif 8821 { 8822 delete _PParam; 8823 } 8824 } 8825 else 8826 { 8827 _CONCRT_ASSERT(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled); 8828 if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled) 8829 { 8830 if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder())) 8831 { 8832 // This can only enter once. 8833 _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState; 8834 _CONCRT_ASSERT(_PParam->_M_exceptionRelatedToken); 8835 // Deref token will be done in the _PParam destructor. 8836 if (_PParam->_M_exceptionRelatedToken != Concurrency::details::_CancellationTokenState::_None()) 8837 { 8838 _PParam->_M_exceptionRelatedToken->_Reference(); 8839 } 8840 } 8841 } 8842 8843 #if _MSC_VER >= 1800 8844 if (Concurrency::details::atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks) 8845 #else 8846 if (_InterlockedIncrementSizeT(&_PParam->_M_completeCount) == _PParam->_M_numTasks) 8847 #endif 8848 { 8849 // If no one has be completed so far, we need to make some final cancellation decision. 8850 if (!_PParam->_M_Completed._IsTriggered()) 8851 { 8852 // If we already explicit token, we can skip the token join part. 8853 if (!_PParam->_M_fHasExplicitToken) 8854 { 8855 if (_PParam->_M_exceptionRelatedToken) 8856 { 8857 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken); 8858 } 8859 else 8860 { 8861 // If haven't captured any exception token yet, there was no exception for all those tasks, 8862 // so just pick a random token (current one) for normal cancellation. 8863 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState); 8864 } 8865 } 8866 // Do exception cancellation or normal cancellation based on whether it has stored exception. 8867 _PParam->_M_Completed._Cancel(); 8868 } 8869 delete _PParam; 8870 } 8871 } 8872 } 8873 8874 template<typename _ElementType, typename _Iterator> 8875 struct _WhenAnyImpl 8876 { 8877 #if _MSC_VER >= 1800 8878 static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) 8879 #else 8880 static task<std::pair<_ElementType, size_t>> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End) 8881 #endif 8882 { 8883 if (_Begin == _End) 8884 { 8885 throw Concurrency::invalid_operation("when_any(begin, end) cannot be called on an empty container."); 8886 } 8887 #if _MSC_VER >= 1800 8888 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 8889 #endif 8890 auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>>(); 8891 8892 if (_PTokenState) 8893 { 8894 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); 8895 _PParam->_M_fHasExplicitToken = true; 8896 } 8897 #if _MSC_VER >= 1800 8898 task_options _Options(_TaskOptions); 8899 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); 8900 task<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options); 8901 #else 8902 task<std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 8903 _Any_tasks_completed._GetImpl()->_M_fRuntimeAggregate = true; 8904 #endif 8905 // Keep a copy ref to the token source 8906 auto _CancellationSource = _PParam->_M_cancellationSource; 8907 8908 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End)); 8909 size_t index = 0; 8910 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8911 { 8912 if (_PTask->is_apartment_aware()) 8913 { 8914 _Any_tasks_completed._SetAsync(); 8915 } 8916 8917 _PTask->_Then([_PParam, index](task<_ElementType> _ResultTask) -> HRESULT { 8918 #if _MSC_VER >= 1800 8919 auto _PParamCopy = _PParam; // Dev10 8920 auto _IndexCopy = index; // Dev10 8921 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() { 8922 _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), _ResultTask._GetImpl()->_M_pTokenState)); 8923 }; 8924 #else 8925 auto _Func = [&_ResultTask, _PParam, index]() { 8926 _PParam->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), index), _ResultTask._GetImpl()->_M_pTokenState)); 8927 }; 8928 #endif 8929 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 8930 return S_OK; 8931 #if _MSC_VER >= 1800 8932 }, Concurrency::details::_CancellationTokenState::_None()); 8933 #else 8934 }, Concurrency::details::_CancellationTokenState::_None(), false); 8935 #endif 8936 index++; 8937 } 8938 8939 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. 8940 return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, Concurrency::details::_CancellationTokenState *> _Result, std::pair<_ElementType, size_t>* retVal) -> HRESULT { 8941 _CONCRT_ASSERT(_Result.second); 8942 if (!_PTokenState) 8943 { 8944 details::_JoinAllTokens_Add(_CancellationSource, _Result.second); 8945 } 8946 *retVal = _Result.first; 8947 return S_OK; 8948 #if _MSC_VER >= 1800 8949 }, nullptr); 8950 #else 8951 }, nullptr, true); 8952 #endif 8953 } 8954 }; 8955 8956 template<typename _Iterator> 8957 struct _WhenAnyImpl<void, _Iterator> 8958 { 8959 #if _MSC_VER >= 1800 8960 static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End) 8961 #else 8962 static task<size_t> _Perform(Concurrency::details::_CancellationTokenState *_PTokenState, _Iterator _Begin, _Iterator _End) 8963 #endif 8964 { 8965 if (_Begin == _End) 8966 { 8967 throw Concurrency::invalid_operation("when_any(begin, end) cannot be called on an empty container."); 8968 } 8969 #if _MSC_VER >= 1800 8970 Concurrency::details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr; 8971 #endif 8972 auto _PParam = new _RunAnyParam<std::pair<size_t, Concurrency::details::_CancellationTokenState *>>(); 8973 8974 if (_PTokenState) 8975 { 8976 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState); 8977 _PParam->_M_fHasExplicitToken = true; 8978 } 8979 8980 #if _MSC_VER >= 1800 8981 task_options _Options(_TaskOptions); 8982 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token()); 8983 task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options); 8984 #else 8985 task<std::pair<size_t, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 8986 #endif 8987 // Keep a copy ref to the token source 8988 auto _CancellationSource = _PParam->_M_cancellationSource; 8989 8990 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End)); 8991 size_t index = 0; 8992 for (auto _PTask = _Begin; _PTask != _End; ++_PTask) 8993 { 8994 if (_PTask->is_apartment_aware()) 8995 { 8996 _Any_tasks_completed._SetAsync(); 8997 } 8998 8999 _PTask->_Then([_PParam, index](task<void> _ResultTask) -> HRESULT { 9000 #if _MSC_VER >= 1800 9001 auto _PParamCopy = _PParam; // Dev10 9002 auto _IndexCopy = index; // Dev10 9003 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() { 9004 _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState)); 9005 }; 9006 #else 9007 auto _Func = [&_ResultTask, _PParam, index]() { 9008 _PParam->_M_Completed.set(std::make_pair(index, _ResultTask._GetImpl()->_M_pTokenState)); 9009 }; 9010 #endif 9011 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 9012 return S_OK; 9013 #if _MSC_VER >= 1800 9014 }, Concurrency::details::_CancellationTokenState::_None()); 9015 #else 9016 }, Concurrency::details::_CancellationTokenState::_None(), false); 9017 #endif 9018 9019 index++; 9020 } 9021 9022 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created. 9023 return _Any_tasks_completed._Then([=](std::pair<size_t, Concurrency::details::_CancellationTokenState *> _Result, size_t* retVal) -> HRESULT { 9024 _CONCRT_ASSERT(_Result.second); 9025 if (!_PTokenState) 9026 { 9027 details::_JoinAllTokens_Add(_CancellationSource, _Result.second); 9028 } 9029 *retVal = _Result.first; 9030 return S_OK; 9031 #if _MSC_VER >= 1800 9032 }, nullptr); 9033 #else 9034 }, nullptr, false); 9035 #endif 9036 } 9037 }; 9038 } // namespace details 9039 9040 /// <summary> 9041 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. 9042 /// </summary> 9043 /// <typeparam name="_Iterator"> 9044 /// The type of the input iterator. 9045 /// </typeparam> 9046 /// <param name="_Begin"> 9047 /// The position of the first element in the range of elements to be combined into the resulting task. 9048 /// </param> 9049 /// <param name="_End"> 9050 /// The position of the first element beyond the range of elements to be combined into the resulting task. 9051 /// </param> 9052 /// <returns> 9053 /// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9054 /// the output of this function will be a <c>task<std::pair<T, size_t>>></c>, where the first element of the pair is the result 9055 /// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c> 9056 /// the output is a <c>task<size_t></c>, where the result is the index of the completing task. 9057 /// </returns> 9058 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9059 /**/ 9060 template<typename _Iterator> 9061 #if _MSC_VER >= 1800 9062 auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options()) 9063 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End)) 9064 { 9065 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 9066 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End); 9067 } 9068 #else 9069 auto when_any(_Iterator _Begin, _Iterator _End) 9070 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(nullptr, _Begin, _End)) 9071 { 9072 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 9073 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(nullptr, _Begin, _End); 9074 } 9075 #endif 9076 9077 /// <summary> 9078 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. 9079 /// </summary> 9080 /// <typeparam name="_Iterator"> 9081 /// The type of the input iterator. 9082 /// </typeparam> 9083 /// <param name="_Begin"> 9084 /// The position of the first element in the range of elements to be combined into the resulting task. 9085 /// </param> 9086 /// <param name="_End"> 9087 /// The position of the first element beyond the range of elements to be combined into the resulting task. 9088 /// </param> 9089 /// <param name="_CancellationToken"> 9090 /// The cancellation token which controls cancellation of the returned task. If you do not provide a cancellation token, the resulting 9091 /// task will receive the cancellation token of the task that causes it to complete. 9092 /// </param> 9093 /// <returns> 9094 /// A task that completes successfully when any one of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9095 /// the output of this function will be a <c>task<std::pair<T, size_t>>></c>, where the first element of the pair is the result 9096 /// of the completing task, and the second element is the index of the task that finished. If the input tasks are of type <c>void</c> 9097 /// the output is a <c>task<size_t></c>, where the result is the index of the completing task. 9098 /// </returns> 9099 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9100 /**/ 9101 template<typename _Iterator> 9102 auto when_any(_Iterator _Begin, _Iterator _End, Concurrency::cancellation_token _CancellationToken) 9103 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End)) 9104 { 9105 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType; 9106 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End); 9107 } 9108 9109 /// <summary> 9110 /// Creates a task that will complete successfully when either of the tasks supplied as arguments completes successfully. 9111 /// </summary> 9112 /// <typeparam name="_ReturnType"> 9113 /// The type of the returned task. 9114 /// </typeparam> 9115 /// <param name="_Lhs"> 9116 /// The first task to combine into the resulting task. 9117 /// </param> 9118 /// <param name="_Rhs"> 9119 /// The second task to combine into the resulting task. 9120 /// </param> 9121 /// <returns> 9122 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9123 /// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task 9124 /// will also be a <c>task<void></c>. 9125 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence 9126 /// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c> 9127 /// and the other one is of type <c>task<T>.</para> 9128 /// </returns> 9129 /// <remarks> 9130 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, 9131 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task. 9132 /// </remarks> 9133 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9134 /**/ 9135 template<typename _ReturnType> 9136 task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs) 9137 { 9138 #if _MSC_VER >= 1800 9139 auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>(); 9140 9141 task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 9142 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, 9143 // So that _PParam can be used before it getting deleted. 9144 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret, _ReturnType* retVal) -> HRESULT { 9145 _CONCRT_ASSERT(_Ret.second); 9146 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<Concurrency::details::_CancellationTokenState *>(_Ret.second)); 9147 *retVal = _Ret.first; 9148 return S_OK; 9149 }, nullptr); 9150 #else 9151 auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *>>(); 9152 9153 task<std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 9154 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, 9155 // So that _PParam can be used before it getting deleted. 9156 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, Concurrency::details::_CancellationTokenState *> _Ret, _ReturnType* retVal) -> HRESULT { 9157 _CONCRT_ASSERT(_Ret.second); 9158 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); 9159 *retVal = _Ret.first; 9160 return S_OK; 9161 }, nullptr, false); 9162 #endif 9163 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) 9164 { 9165 _ReturnTask._SetAsync(); 9166 } 9167 9168 _PParam->_M_numTasks = 2; 9169 auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) -> HRESULT { 9170 #if _MSC_VER >= 1800 9171 // Dev10 compiler bug 9172 auto _PParamCopy = _PParam; 9173 auto _Func = [&_ResultTask, _PParamCopy]() { 9174 _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState))); 9175 }; 9176 #else 9177 auto _Func = [&_ResultTask, _PParam]() { 9178 _PParam->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _ResultTask._GetImpl()->_M_pTokenState)); 9179 }; 9180 #endif 9181 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 9182 return S_OK; 9183 }; 9184 9185 #if _MSC_VER >= 1800 9186 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None()); 9187 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None()); 9188 #else 9189 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false); 9190 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false); 9191 #endif 9192 return _ReturnTask; 9193 } 9194 9195 /// <summary> 9196 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. 9197 /// </summary> 9198 /// <typeparam name="_ReturnType"> 9199 /// The type of the returned task. 9200 /// </typeparam> 9201 /// <param name="_Lhs"> 9202 /// The first task to combine into the resulting task. 9203 /// </param> 9204 /// <param name="_Rhs"> 9205 /// The second task to combine into the resulting task. 9206 /// </param> 9207 /// <returns> 9208 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9209 /// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task 9210 /// will also be a <c>task<void></c>. 9211 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence 9212 /// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c> 9213 /// and the other one is of type <c>task<T>.</para> 9214 /// </returns> 9215 /// <remarks> 9216 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, 9217 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task. 9218 /// </remarks> 9219 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9220 /**/ 9221 template<typename _ReturnType> 9222 task<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs) 9223 { 9224 auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *>>(); 9225 9226 task<std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 9227 #if _MSC_VER < 1800 9228 _Any_tasks_completed._GetImpl()->_M_fRuntimeAggregate = true; 9229 #endif 9230 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, 9231 // So that _PParam can be used before it getting deleted. 9232 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, Concurrency::details::_CancellationTokenState *> _Ret, std::vector<_ReturnType>* retVal) -> HRESULT { 9233 _CONCRT_ASSERT(_Ret.second); 9234 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); 9235 *retVal = _Ret.first; 9236 return S_OK; 9237 }, nullptr, true); 9238 9239 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) 9240 { 9241 _ReturnTask._SetAsync(); 9242 } 9243 9244 _PParam->_M_numTasks = 2; 9245 _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) -> HRESULT { 9246 #if _MSC_VER >= 1800 9247 // Dev10 compiler bug 9248 auto _PParamCopy = _PParam; 9249 auto _Func = [&_ResultTask, _PParamCopy]() { 9250 auto _Result = _ResultTask._GetImpl()->_GetResult(); 9251 _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState)); 9252 }; 9253 #else 9254 auto _Func = [&_ResultTask, _PParam]() { 9255 std::vector<_ReturnType> _Result = _ResultTask._GetImpl()->_GetResult(); 9256 _PParam->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState)); 9257 }; 9258 #endif 9259 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 9260 return S_OK; 9261 #if _MSC_VER >= 1800 9262 }, Concurrency::details::_CancellationTokenState::_None()); 9263 #else 9264 }, Concurrency::details::_CancellationTokenState::_None(), false); 9265 #endif 9266 _Rhs._Then([_PParam](task<_ReturnType> _ResultTask) -> HRESULT { 9267 #if _MSC_VER >= 1800 9268 // Dev10 compiler bug 9269 typedef _ReturnType _ReturnTypeDev10; 9270 auto _PParamCopy = _PParam; 9271 auto _Func = [&_ResultTask, _PParamCopy]() { 9272 auto _Result = _ResultTask._GetImpl()->_GetResult(); 9273 9274 std::vector<_ReturnTypeDev10> _Vec; 9275 _Vec.push_back(_Result); 9276 _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState)); 9277 }; 9278 #else 9279 auto _Func = [&_ResultTask, _PParam]() { 9280 _ReturnType _Result = _ResultTask._GetImpl()->_GetResult(); 9281 9282 std::vector<_ReturnType> _Vec; 9283 _Vec.push_back(_Result); 9284 _PParam->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState)); 9285 }; 9286 #endif 9287 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 9288 return S_OK; 9289 #if _MSC_VER >= 1800 9290 }, Concurrency::details::_CancellationTokenState::_None()); 9291 #else 9292 }, Concurrency::details::_CancellationTokenState::_None(), false); 9293 #endif 9294 return _ReturnTask; 9295 } 9296 9297 /// <summary> 9298 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. 9299 /// </summary> 9300 /// <typeparam name="_ReturnType"> 9301 /// The type of the returned task. 9302 /// </typeparam> 9303 /// <param name="_Lhs"> 9304 /// The first task to combine into the resulting task. 9305 /// </param> 9306 /// <param name="_Rhs"> 9307 /// The second task to combine into the resulting task. 9308 /// </param> 9309 /// <returns> 9310 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9311 /// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task 9312 /// will also be a <c>task<void></c>. 9313 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence 9314 /// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c> 9315 /// and the other one is of type <c>task<T>.</para> 9316 /// </returns> 9317 /// <remarks> 9318 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, 9319 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task. 9320 /// </remarks> 9321 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9322 /**/ 9323 template<typename _ReturnType> 9324 task<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs) 9325 { 9326 return _Rhs || _Lhs; 9327 } 9328 9329 /// <summary> 9330 /// Creates a task that will complete successfully when any of the tasks supplied as arguments completes successfully. 9331 /// </summary> 9332 /// <typeparam name="_ReturnType"> 9333 /// The type of the returned task. 9334 /// </typeparam> 9335 /// <param name="_Lhs"> 9336 /// The first task to combine into the resulting task. 9337 /// </param> 9338 /// <param name="_Rhs"> 9339 /// The second task to combine into the resulting task. 9340 /// </param> 9341 /// <returns> 9342 /// A task that completes sucessfully when either of the input tasks has completed successfully. If the input tasks are of type <c>T</c>, 9343 /// the output of this function will be a <c>task<std::vector<T></c>. If the input tasks are of type <c>void</c> the output task 9344 /// will also be a <c>task<void></c>. 9345 /// <para> To allow for a construct of the sort taskA || taskB && taskC, which are combined in pairs, with && taking precedence 9346 /// over ||, the operator|| produces a <c>task<std::vector<T>></c> if one of the tasks is of type <c>task<std::vector<T>></c> 9347 /// and the other one is of type <c>task<T>.</para> 9348 /// </returns> 9349 /// <remarks> 9350 /// If both of the tasks are canceled or throw exceptions, the returned task will complete in the canceled state, and one of the exceptions, 9351 /// if any are encountered, will be thrown when you call <c>get()</c> or <c>wait()</c> on that task. 9352 /// </remarks> 9353 /// <seealso cref="Task Parallelism (Concurrency Runtime)"/> 9354 /**/ 9355 inline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs) 9356 { 9357 auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *>>(); 9358 9359 task<std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token()); 9360 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called, 9361 // So that _PParam can be used before it getting deleted. 9362 auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, Concurrency::details::_CancellationTokenState *> _Ret) -> HRESULT { 9363 _CONCRT_ASSERT(_Ret.second); 9364 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second); 9365 return S_OK; 9366 #if _MSC_VER >= 1800 9367 }, nullptr); 9368 #else 9369 }, nullptr, false); 9370 #endif 9371 9372 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware()) 9373 { 9374 _ReturnTask._SetAsync(); 9375 } 9376 9377 _PParam->_M_numTasks = 2; 9378 auto _Continuation = [_PParam](task<void> _ResultTask) mutable -> HRESULT { 9379 // Dev10 compiler needs this. 9380 auto _PParam1 = _PParam; 9381 auto _Func = [&_ResultTask, _PParam1]() { 9382 _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState)); 9383 }; 9384 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask); 9385 return S_OK; 9386 }; 9387 9388 #if _MSC_VER >= 1800 9389 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None()); 9390 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None()); 9391 #else 9392 _Lhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false); 9393 _Rhs._Then(_Continuation, Concurrency::details::_CancellationTokenState::_None(), false); 9394 #endif 9395 9396 return _ReturnTask; 9397 } 9398 9399 #if _MSC_VER >= 1800 9400 template<typename _Ty> 9401 task<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options()) 9402 { 9403 task_completion_event<_Ty> _Tce; 9404 _Tce.set(_Param); 9405 return create_task<_Ty>(_Tce, _TaskOptions); 9406 } 9407 9408 // Work around VS 2010 compiler bug 9409 #if _MSC_VER == 1600 9410 inline task<bool> task_from_result(bool _Param) 9411 { 9412 task_completion_event<bool> _Tce; 9413 _Tce.set(_Param); 9414 return create_task<bool>(_Tce, task_options()); 9415 } 9416 #endif 9417 inline task<void> task_from_result(const task_options& _TaskOptions = task_options()) 9418 { 9419 task_completion_event<void> _Tce; 9420 _Tce.set(); 9421 return create_task<void>(_Tce, _TaskOptions); 9422 } 9423 9424 template<typename _TaskType, typename _ExType> 9425 task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options()) 9426 { 9427 task_completion_event<_TaskType> _Tce; 9428 _Tce.set_exception(_Exception); 9429 return create_task<_TaskType>(_Tce, _TaskOptions); 9430 } 9431 9432 namespace details 9433 { 9434 /// <summary> 9435 /// A convenient extension to Concurrency: loop until a condition is no longer met 9436 /// </summary> 9437 /// <param name="func"> 9438 /// A function representing the body of the loop. It will be invoked at least once and 9439 /// then repetitively as long as it returns true. 9440 /// </param> 9441 inline 9442 task<bool> do_while(std::function<task<bool>(void)> func) 9443 { 9444 task<bool> first = func(); 9445 return first.then([=](bool guard, task<bool>* retVal) -> HRESULT { 9446 if (guard) 9447 *retVal = do_while(func); 9448 else 9449 *retVal = first; 9450 return S_OK; 9451 }); 9452 } 9453 9454 } // namespace details 9455 #endif 9456 9457 } // namespace Concurrency_winrt 9458 9459 namespace concurrency_winrt = Concurrency_winrt; 9460 9461 #pragma pop_macro("new") 9462 #pragma warning(pop) 9463 #pragma pack(pop) 9464 #endif 9465 9466 #endif 9467