1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * ==--==
17 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18 *
19 * Parallel Patterns Library - PPLx Tasks
20 *
21 * For the latest on this and related APIs, please see http://casablanca.codeplex.com.
22 *
23 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
24 ****/
25
26 #pragma once
27
28 #ifndef _PPLXTASKS_H
29 #define _PPLXTASKS_H
30
31 #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) && !CPPREST_FORCE_PPLX
32 #include <ppltasks.h>
34 #if (_MSC_VER >= 1900)
35 #include <concrt.h>
37 namespace extensibility {
38 typedef ::std::condition_variable condition_variable_t;
39 typedef ::std::mutex critical_section_t;
40 typedef ::std::unique_lock< ::std::mutex> scoped_critical_section_t;
41
42 typedef ::Concurrency::event event_t;
43 typedef ::Concurrency::reader_writer_lock reader_writer_lock_t;
44 typedef ::Concurrency::reader_writer_lock::scoped_lock scoped_rw_lock_t;
45 typedef ::Concurrency::reader_writer_lock::scoped_lock_read scoped_read_lock_t;
46
47 typedef ::Concurrency::details::_ReentrantBlockingLock recursive_lock_t;
48 typedef recursive_lock_t::_Scoped_lock scoped_recursive_lock_t;
49 }
50 }
51 #endif // _MSC_VER >= 1900
52 #else
53
54 #include "pplx/pplx.h"
55
56 #if defined(__ANDROID__)
57 #include <jni.h>
58 void cpprest_init(JavaVM*);
59 #endif
60
61 // Cannot build using a compiler that is older than dev10 SP1
62 #if defined(_MSC_VER)
63 #if _MSC_FULL_VER < 160040219 /*IFSTRIP=IGN*/
64 #error ERROR: Visual Studio 2010 SP1 or later is required to build ppltasks
65 #endif /*IFSTRIP=IGN*/
66 #endif /* defined(_MSC_VER) */
67
68 #include <functional>
69 #include <vector>
70 #include <utility>
71 #include <exception>
72 #include <algorithm>
73
74 #if defined(_MSC_VER)
75 #if defined(__cplusplus_winrt)
76 #include <windows.h>
77 #include <ctxtcall.h>
78 #include <agile.h>
79 #include <winapifamily.h>
80 #ifndef _UITHREADCTXT_SUPPORT
81
82 #ifdef WINAPI_FAMILY /*IFSTRIP=IGN*/
83
84 // It is safe to include winapifamily as WINAPI_FAMILY was defined by the user
85 #include <winapifamily.h>
86
87 #if WINAPI_FAMILY == WINAPI_FAMILY_APP
88 // UI thread context support is not required for desktop and Windows Store apps
89 #define _UITHREADCTXT_SUPPORT 0
90 #elif WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
91 // UI thread context support is not required for desktop and Windows Store apps
92 #define _UITHREADCTXT_SUPPORT 0
93 #else /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
94 #define _UITHREADCTXT_SUPPORT 1
95 #endif /* WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP */
96
97 #else /* WINAPI_FAMILY */
98 // Not supported without a WINAPI_FAMILY setting.
99 #define _UITHREADCTXT_SUPPORT 0
100 #endif /* WINAPI_FAMILY */
101
102 #endif /* _UITHREADCTXT_SUPPORT */
103
104 #if _UITHREADCTXT_SUPPORT
105 #include <uithreadctxt.h>
106 #endif /* _UITHREADCTXT_SUPPORT */
107
108 #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "1")
109 #else /* defined(__cplusplus_winrt) */
110 #pragma detect_mismatch("_PPLTASKS_WITH_WINRT", "0")
111 #endif /* defined(__cplusplus_winrt) */
112 #endif /* defined(_MSC_VER) */
113
114 #ifdef _DEBUG
115 #define _DBG_ONLY(X) X
116 #else
117 #define _DBG_ONLY(X)
118 #endif // #ifdef _DEBUG
119
120 // std::copy_exception changed to std::make_exception_ptr from VS 2010 to VS 11.
121 #ifdef _MSC_VER
122 #if _MSC_VER < 1700 /*IFSTRIP=IGN*/
123 namespace std
124 {
125 template<class _E> exception_ptr make_exception_ptr(_E _Except)
126 {
127 return copy_exception(_Except);
128 }
129 }
130 #endif /* _MSC_VER < 1700 */
131 #ifndef _PPLTASK_ASYNC_LOGGING
132 #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
133 #define _PPLTASK_ASYNC_LOGGING 1 // Only enable async logging under dev12 winrt
134 #else
135 #define _PPLTASK_ASYNC_LOGGING 0
136 #endif
137 #endif /* !_PPLTASK_ASYNC_LOGGING */
138 #endif /* _MSC_VER */
139
140 #pragma pack(push,_CRT_PACKING)
141
142 #if defined(_MSC_VER)
143 #pragma warning(push)
144 #pragma warning(disable: 28197)
145 #pragma warning(disable: 4100) // Unreferenced formal parameter - needed for document generation
146 #pragma warning(disable: 4127) // constant express in if condition - we use it for meta programming
147 #endif /* defined(_MSC_VER) */
148
149 // All CRT public header files are required to be protected from the macro new
150 #pragma push_macro("new")
151 #undef new
152
153 // stuff ported from Dev11 CRT
154 // NOTE: this doesn't actually match std::declval. it behaves differently for void!
155 // so don't blindly change it to std::declval.
157 {
158 template<class _T>
159 _T&& declval();
160 }
161
166
168 {
173
175
176 template <
typename _Type>
class task;
177 template <>
class task<void>;
178
179 // 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.
180 #ifndef PPL_TASK_SAVE_FRAME_COUNT
181 #ifdef _DEBUG
182 #define PPL_TASK_SAVE_FRAME_COUNT 10
183 #else
184 #define PPL_TASK_SAVE_FRAME_COUNT 1
185 #endif
186 #endif
187
196 #if PPL_TASK_SAVE_FRAME_COUNT > 1
197 #if defined(__cplusplus_winrt) && !defined(_DEBUG)
198 #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!")
199 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
200 #else
201 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureMultiFramesCallstack(PPL_TASK_SAVE_FRAME_COUNT)
202 #endif
203 #else
204 #define _CAPTURE_CALLSTACK() ::pplx::details::_TaskCreationCallstack::_CaptureSingleFrameCallstack(_ReturnAddress())
205 #endif
206
207
229
231 {
232 return ::pplx::details::_TaskCollection_t::_Is_cancellation_requested();
233 }
234
244
245 inline __declspec(noreturn) void _pplx_cdecl cancel_current_task()
246 {
248 }
249
250 namespace details
251 {
258 {
259 private:
260 // If _M_SingleFrame != nullptr, there will be only one frame of callstacks, which is stored in _M_SingleFrame;
261 // otherwise, _M_Frame will store all the callstack frames.
262 void* _M_SingleFrame;
263 std::vector<void *> _M_frames;
264 public:
266 {
267 _M_SingleFrame = nullptr;
268 }
269
270 // Store one frame of callstack. This function works for both Debug / Release CRT.
272 {
274 _csc._M_SingleFrame = _SingleFrame;
275 return _csc;
276 }
277
278 // Capture _CaptureFrames number of callstack frames. This function only work properly for Desktop or Debug CRT.
279 __declspec(noinline)
281 {
283 _csc._M_frames.resize(_CaptureFrames);
284 // skip 2 frames to make sure callstack starts from user code
285 _csc._M_frames.resize(::pplx::details::platform::CaptureCallstack(&_csc._M_frames[0], 2, _CaptureFrames));
286 return _csc;
287 }
288 };
289 typedef unsigned char _Unit_type;
290
298
299 template<typename _Ty>
301 {
302 typedef _Ty _Type;
303 };
304
305 template<>
307 {
308 typedef _Unit_type _Type;
309 };
310
311 template<typename _T>
313 {
314 static const bool _Value = true;
315 };
316
317 template<>
319 {
320 static const bool _Value = false;
321 };
322
323 template <typename _Ty>
325 {
326 typedef _Ty _Type;
327 };
328
329 template <typename _Ty>
331 {
332 typedef _Ty _Type;
333 };
334
335 template <typename _T>
337
339
340 #if defined(__cplusplus_winrt)
341 template <typename _Type>
342 struct _Unhat
343 {
344 typedef _Type _Value;
345 };
346
347 template <typename _Type>
348 struct _Unhat<_Type^>
349 {
350 typedef _Type _Value;
351 };
352
353 value struct _NonUserType { public: int _Dummy; };
354
355 template <typename _Type, bool _IsValueTypeOrRefType = __is_valid_winrt_type(_Type)>
356 struct _ValueTypeOrRefType
357 {
358 typedef _NonUserType _Value;
359 };
360
361 template <typename _Type>
362 struct _ValueTypeOrRefType<_Type, true>
363 {
364 typedef _Type _Value;
365 };
366
367 template <typename _T1, typename _T2>
368 _T2 _ProgressTypeSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1,_T2>^);
369
370 template <typename _T1>
371 _T1 _ProgressTypeSelector(Windows::Foundation::IAsyncActionWithProgress<_T1>^);
372
373 template <typename _Type>
374 struct _GetProgressType
375 {
376 typedef decltype(_ProgressTypeSelector(stdx::declval<_Type>())) _Value;
377 };
378
379 template <typename _Type>
380 struct _IsIAsyncInfo
381 {
382 static const bool _Value = __is_base_of(Windows::Foundation::IAsyncInfo, typename _Unhat<_Type>::_Value);
383 };
384
385 template <typename _T>
386 _TypeSelectorAsyncOperation _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperation<_T>^);
387
388 _TypeSelectorAsyncAction _AsyncOperationKindSelector(Windows::Foundation::IAsyncAction^);
389
390 template <typename _T1, typename _T2>
391 _TypeSelectorAsyncOperationWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncOperationWithProgress<_T1, _T2>^);
392
393 template <typename _T>
394 _TypeSelectorAsyncActionWithProgress _AsyncOperationKindSelector(Windows::Foundation::IAsyncActionWithProgress<_T>^);
395
396 template <typename _Type, bool _IsAsync = _IsIAsyncInfo<_Type>::_Value>
397 struct _TaskTypeTraits
398 {
399 typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;
400 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
401 typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
402
403 static const bool _IsAsyncTask = _IsAsync;
404 static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
405 };
406
407 template<typename _Type>
408 struct _TaskTypeTraits<_Type, true >
409 {
410 typedef decltype(((_Type)nullptr)->GetResults()) _TaskRetType;
411 typedef _TaskRetType _NormalizedTaskRetType;
412 typedef decltype(_AsyncOperationKindSelector((_Type)nullptr)) _AsyncKind;
413
414 static const bool _IsAsyncTask = true;
415 static const bool _IsUnwrappedTaskOrAsync = _IsUnwrappedAsyncSelector<_AsyncKind>::_Value;
416 };
417
418 #else /* defined (__cplusplus_winrt) */
419 template <typename _Type>
421 {
422 static const bool _Value = false;
423 };
424
425 template <typename _Type, bool _IsAsync = false>
427 {
428 typedef typename _UnwrapTaskType<_Type>::_Type _TaskRetType;
429 typedef decltype(_AsyncOperationKindSelector(stdx::declval<_Type>())) _AsyncKind;
430 typedef typename _NormalizeVoidToUnitType<_TaskRetType>::_Type _NormalizedTaskRetType;
431
432 static const bool _IsAsyncTask = false;
434 };
435 #endif /* defined (__cplusplus_winrt) */
436
437 template <typename _Function> auto _IsCallable(_Function _Func, int) -> decltype(_Func(), std::true_type()) { (void)(_Func); return std::true_type(); }
438 template <typename _Function> std::false_type _IsCallable(_Function, ...) { return std::false_type(); }
439
440 template <>
442 {
443 typedef void _TaskRetType;
445 typedef _Unit_type _NormalizedTaskRetType;
446
447 static const bool _IsAsyncTask = false;
448 static const bool _IsUnwrappedTaskOrAsync = false;
449 };
450
451 template<typename _Type>
453
454 template<typename _Func>
456
458
459 template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)));
460 template <typename _Function, typename _Type> auto _ReturnTypeHelper(_Type t, _Function _Func, int, ...) -> decltype(_Func(t));
461 template <
typename _Function,
typename _Type>
auto _ReturnTypeHelper(_Type t, _Function _Func, ...) ->
_BadContinuationParamType;
462
463 template <typename _Function, typename _Type> auto _IsTaskHelper(_Type t, _Function _Func, int, int) -> decltype(_Func(_To_task(t)), std::true_type());
464 template <typename _Function, typename _Type> std::false_type _IsTaskHelper(_Type t, _Function _Func, int, ...);
465
466 template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)));
467 template <typename _Function> auto _VoidReturnTypeHelper(_Function _Func, int, ...) -> decltype(_Func());
468
469 template <typename _Function> auto _VoidIsTaskHelper(_Function _Func, int, int) -> decltype(_Func(_To_task_void(_Func)), std::true_type());
470 template <typename _Function> std::false_type _VoidIsTaskHelper(_Function _Func, int, ...);
471
472 template<typename _Function, typename _ExpectedParameterType>
474 {
475 typedef decltype(_ReturnTypeHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _FuncRetType;
476 static_assert(!std::is_same<_FuncRetType,_BadContinuationParamType>::value, "incorrect parameter type for the callable object in 'then'; consider _ExpectedParameterType or task<_ExpectedParameterType> (see below)");
477
478 typedef decltype(_IsTaskHelper(stdx::declval<_ExpectedParameterType>(),stdx::declval<_Function>(), 0, 0)) _Takes_task;
479 };
480
481 template<typename _Function>
483 {
484 typedef decltype(_VoidReturnTypeHelper(stdx::declval<_Function>(), 0, 0)) _FuncRetType;
485 typedef decltype(_VoidIsTaskHelper(stdx::declval<_Function>(), 0, 0)) _Takes_task;
486 };
487
488 template<typename _Function, typename _ReturnType>
490 {
492 };
493
494 // _InitFunctorTypeTraits is used to decide whether a task constructed with a lambda should be unwrapped. Depending on how the variable is
495 // declared, the constructor may or may not perform unwrapping. For eg.
496 //
497 // This declaration SHOULD NOT cause unwrapping
498 // task<task<void>> t1([]() -> task<void> {
499 // task<void> t2([]() {});
500 // return t2;
501 // });
502 //
503 // This declaration SHOULD cause unwrapping
504 // task<void>> t1([]() -> task<void> {
505 // task<void> t2([]() {});
506 // return t2;
507 // });
508 // 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.
509 template <typename _TaskType, typename _FuncRetType>
511 {
515 };
516
517 template<typename T>
519 {
521 static const bool _IsAsyncTask = false;
522 static const bool _IsUnwrappedTaskOrAsync = false;
523 };
524
529 {
531 _M_func(_Callback)
532 {
533 }
534
535 static void _pplx_cdecl _Bridge(void *_PData)
536 {
538 _Holder _ThunkHolder(_PThunk);
539 _PThunk->_M_func();
540 }
541 private:
542
543 // RAII holder
544 struct _Holder
545 {
547 {
548 }
549
550 ~_Holder()
551 {
552 delete _M_pThunk;
553 }
554
556
557 private:
558 _Holder& operator=(const _Holder&);
559 };
560
561 std::function<void()> _M_func;
563 };
564
576 static void _ScheduleFuncWithAutoInline(const std::function<void ()> & _Func, _TaskInliningMode_t _InliningMode)
577 {
578 _TaskCollection_t::_RunTask(&_TaskProcThunk::_Bridge,
new _TaskProcThunk(_Func), _InliningMode);
579 }
580
582 {
583 typedef std::function<void(void)> _CallbackFunction;
584
585 #if defined (__cplusplus_winrt)
586
587 public:
588
590 {
592 _Context._Capture();
593 return _Context;
594 }
595
597 {
598 _Reset();
599 }
600
602 {
603 if (_DeferCapture)
604 {
605 _M_context._M_captureMethod = _S_captureDeferred;
606 }
607 else
608 {
609 _M_context._M_pContextCallback = nullptr;
610 }
611 }
612
613 // Resolves a context that was created as _S_captureDeferred based on the environment (ancestor, current context).
614 void _Resolve(bool _CaptureCurrent)
615 {
616 if(_M_context._M_captureMethod == _S_captureDeferred)
617 {
618 _M_context._M_pContextCallback = nullptr;
619
620 if (_CaptureCurrent)
621 {
622 if (_IsCurrentOriginSTA())
623 {
624 _Capture();
625 }
626 #if _UITHREADCTXT_SUPPORT
627 else
628 {
629 // This method will fail if not called from the UI thread.
630 HRESULT _Hr = CaptureUiThreadContext(&_M_context._M_pContextCallback);
631 if (FAILED(_Hr))
632 {
633 _M_context._M_pContextCallback = nullptr;
634 }
635 }
636 #endif /* _UITHREADCTXT_SUPPORT */
637 }
638 }
639 }
640
641 void _Capture()
642 {
643 HRESULT _Hr = CoGetObjectContext(IID_IContextCallback, reinterpret_cast<void **>(&_M_context._M_pContextCallback));
644 if (FAILED(_Hr))
645 {
646 _M_context._M_pContextCallback = nullptr;
647 }
648 }
649
651 {
652 _Assign(_Src._M_context._M_pContextCallback);
653 }
654
656 {
657 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
658 _Src._M_context._M_pContextCallback = nullptr;
659 }
660
662 {
663 if (this != &_Src)
664 {
665 _Reset();
666 _Assign(_Src._M_context._M_pContextCallback);
667 }
668 return *this;
669 }
670
672 {
673 if (this != &_Src)
674 {
675 _M_context._M_pContextCallback = _Src._M_context._M_pContextCallback;
676 _Src._M_context._M_pContextCallback = nullptr;
677 }
678 return *this;
679 }
680
681 bool _HasCapturedContext() const
682 {
683 _ASSERTE(_M_context._M_captureMethod != _S_captureDeferred);
684 return (_M_context._M_pContextCallback != nullptr);
685 }
686
687 void _CallInContext(_CallbackFunction _Func) const
688 {
689 if (!_HasCapturedContext())
690 {
691 _Func();
692 }
693 else
694 {
695 ComCallData callData;
696 ZeroMemory(&callData, sizeof(callData));
697 callData.pUserDefined = reinterpret_cast<void *>(&_Func);
698
699 HRESULT _Hr = _M_context._M_pContextCallback->ContextCallback(&_Bridge, &callData, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr);
700 if (FAILED(_Hr))
701 {
702 throw ::Platform::Exception::CreateException(_Hr);
703 }
704 }
705 }
706
708 {
709 return (_M_context._M_pContextCallback == _Rhs._M_context._M_pContextCallback);
710 }
711
713 {
714 return !(operator==(_Rhs));
715 }
716
717 private:
718 void _Reset()
719 {
720 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
721 {
722 _M_context._M_pContextCallback->Release();
723 }
724 }
725
726 void _Assign(IContextCallback *_PContextCallback)
727 {
728 _M_context._M_pContextCallback = _PContextCallback;
729 if (_M_context._M_captureMethod != _S_captureDeferred && _M_context._M_pContextCallback != nullptr)
730 {
731 _M_context._M_pContextCallback->AddRef();
732 }
733 }
734
735 static HRESULT __stdcall _Bridge(ComCallData *_PParam)
736 {
737 _CallbackFunction *pFunc = reinterpret_cast<_CallbackFunction *>(_PParam->pUserDefined);
738 (*pFunc)();
739 return S_OK;
740 }
741
742 // Returns the origin information for the caller (runtime / Windows Runtime apartment as far as task continuations need know)
743 static bool _IsCurrentOriginSTA()
744 {
745 APTTYPE _AptType;
746 APTTYPEQUALIFIER _AptTypeQualifier;
747
748 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
749 if (SUCCEEDED(hr))
750 {
751 // We determine the origin of a task continuation by looking at where .then is called, so we can tell whether
752 // to need to marshal the continuation back to the originating apartment. If an STA thread is in executing in
753 // a neutral aparment when it schedules a continuation, we will not marshal continuations back to the STA,
754 // since variables used within a neutral apartment are expected to be apartment neutral.
755 switch(_AptType)
756 {
757 case APTTYPE_MAINSTA:
758 case APTTYPE_STA:
759 return true;
760 default:
761 break;
762 }
763 }
764 return false;
765 }
766
767 union
768 {
769 IContextCallback *_M_pContextCallback;
770 size_t _M_captureMethod;
771 } _M_context;
772
773 static const size_t _S_captureDeferred = 1;
774 #else /* defined (__cplusplus_winrt) */
775 public:
776
778 {
780 }
781
783 {
784 }
785
787 {
788 }
789
791 {
792 }
793
795 {
796 return *this;
797 }
798
800 {
801 return *this;
802 }
803
804 bool _HasCapturedContext() const
805 {
806 return false;
807 }
808
809 void _Resolve(bool) const
810 {
811 }
812
813 void _CallInContext(_CallbackFunction _Func) const
814 {
815 _Func();
816 }
817
819 {
820 return true;
821 }
822
824 {
825 return false;
826 }
827
828 #endif /* defined (__cplusplus_winrt) */
829 };
830
831 template<typename _Type>
833 {
834 void Set(const _Type& _type)
835 {
836 _Result = _type;
837 }
838
839 _Type Get()
840 {
841 return _Result;
842 }
843
844 _Type _Result;
845 };
846
847 #if defined (__cplusplus_winrt)
848
849 template<typename _Type>
851 {
852 void Set(_Type^ const & _type)
853 {
854 _M_Result = _type;
855 }
856
857 _Type^ Get()
858 {
859 return _M_Result.Get();
860 }
861 private:
862 // ::Platform::Agile handle specialization of all hats
863 // including ::Platform::String and ::Platform::Array
864 ::Platform::Agile<_Type^> _M_Result;
865 };
866
867 //
868 // The below are for composability with tasks auto-created from when_any / when_all / && / || constructs.
869 //
870 template<typename _Type>
871 struct _ResultHolder<std::vector<_Type^>>
872 {
873 void Set(const std::vector<_Type^>& _type)
874 {
875 _Result.reserve(_type.size());
876
877 for (auto _PTask = _type.begin(); _PTask != _type.end(); ++_PTask)
878 {
879 _Result.emplace_back(*_PTask);
880 }
881 }
882
883 std::vector<_Type^> Get()
884 {
885 // Return vectory<T^> with the objects that are marshaled in the proper appartment
886 std::vector<_Type^> _Return;
887 _Return.reserve(_Result.size());
888
889 for (auto _PTask = _Result.begin(); _PTask != _Result.end(); ++_PTask)
890 {
891 _Return.push_back(_PTask->Get()); // Platform::Agile will marshal the object to appropriate appartment if neccessary
892 }
893
894 return _Return;
895 }
896
897 std::vector< ::Platform::Agile<_Type^> > _Result;
898 };
899
900 template<typename _Type>
901 struct _ResultHolder<std::pair<_Type^, void*> >
902 {
903 void Set(const std::pair<_Type^, size_t>& _type)
904 {
905 _M_Result = _type;
906 }
907
908 std::pair<_Type^, size_t> Get()
909 {
910 return std::make_pair(_M_Result.first.Get(), _M_Result.second);
911 }
912 private:
913 std::pair< ::Platform::Agile<_Type^>, size_t> _M_Result;
914 };
915
916 #endif /* defined (__cplusplus_winrt) */
917
918 // 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.
919 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
920 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
922 {
923 private:
924 void ReportUnhandledError()
925 {
926 #if _MSC_VER >= 1800 && defined(__cplusplus_winrt)
927 if (_M_winRTException != nullptr)
928 {
929 ::Platform::Details::ReportUnhandledError(_M_winRTException);
930 }
931 #endif /* defined (__cplusplus_winrt) */
932 }
933 public:
935 _M_exceptionObserved(0), _M_stdException(_E), _M_stackTrace(_stackTrace)
936 #if defined (__cplusplus_winrt)
937 , _M_winRTException(nullptr)
938 #endif /* defined (__cplusplus_winrt) */
939 {
940 }
941
942 #if defined (__cplusplus_winrt)
944 _M_exceptionObserved(0), _M_winRTException(_E), _M_stackTrace(_stackTrace)
945 {
946 }
947 #endif /* defined (__cplusplus_winrt) */
948
951 {
952 if (_M_exceptionObserved == 0)
953 {
954 // If you are trapped here, it means an exception thrown in task chain didn't get handled.
955 // Please add task-based continuation to handle all exceptions coming from tasks.
956 // this->_M_stackTrace keeps the creation callstack of the task generates this exception.
957 _REPORT_PPLTASK_UNOBSERVED_EXCEPTION();
958 }
959 }
960
961 void _RethrowUserException()
962 {
963 if (_M_exceptionObserved == 0)
964 {
965 atomic_exchange(_M_exceptionObserved, 1l);
966 }
967
968 #if defined (__cplusplus_winrt)
969 if (_M_winRTException != nullptr)
970 {
971 throw _M_winRTException;
972 }
973 #endif /* defined (__cplusplus_winrt) */
974 std::rethrow_exception(_M_stdException);
975 }
976
977 // A variable that remembers if this exception was every rethrown into user code (and hence handled by the user). Exceptions that
978 // are unobserved when the exception holder is destructed will terminate the process.
979 atomic_long _M_exceptionObserved;
980
981 // Either _M_stdException or _M_winRTException is populated based on the type of exception encountered.
982 std::exception_ptr _M_stdException;
983 #if defined (__cplusplus_winrt)
984 ::Platform::Exception^ _M_winRTException;
985 #endif /* defined (__cplusplus_winrt) */
986
987 // Disassembling this value will point to a source instruction right after a call instruction. If the call is to create_task,
988 // a task constructor or the then method, the task created by that method is the one that encountered this exception. If the call
989 // is to task_completion_event::set_exception, the set_exception method was the source of the exception.
990 // DO NOT REMOVE THIS VARIABLE. It is extremely helpful for debugging.
992
993 };
994
995 #if defined (__cplusplus_winrt)
996 template<typename _AsyncOperationType, typename _CompletionHandlerType, typename _Result>
1000 ref struct _AsyncInfoImpl abstract : Windows::Foundation::IAsyncOperation<_Result>
1001 {
1002 internal:
1003 // The async action, action with progress or operation with progress that this stub forwards to.
1004 ::Platform::Agile<_AsyncOperationType> _M_asyncInfo;
1005
1006 Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ _M_CompletedHandler;
1007
1008 _AsyncInfoImpl( _AsyncOperationType _AsyncInfo ) : _M_asyncInfo(_AsyncInfo) {}
1009
1010 public:
1011 virtual void Cancel() { _M_asyncInfo.Get()->Cancel(); }
1012 virtual void Close() { _M_asyncInfo.Get()->Close(); }
1013
1014 virtual property Windows::Foundation::HResult ErrorCode
1015 {
1016 Windows::Foundation::HResult get()
1017 {
1018 return _M_asyncInfo.Get()->ErrorCode;
1019 }
1020 }
1021
1022 virtual property UINT Id
1023 {
1024 UINT get()
1025 {
1026 return _M_asyncInfo.Get()->Id;
1027 }
1028 }
1029
1030 virtual property Windows::Foundation::AsyncStatus Status
1031 {
1032 Windows::Foundation::AsyncStatus get()
1033 {
1034 return _M_asyncInfo.Get()->Status;
1035 }
1036 }
1037
1038 virtual _Result GetResults() { throw std::runtime_error("derived class must implement"); }
1039
1040 virtual property Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ Completed
1041 {
1042 Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ get()
1043 {
1044 return _M_CompletedHandler;
1045 }
1046
1047 void set(Windows::Foundation::AsyncOperationCompletedHandler<_Result>^ value)
1048 {
1049 _M_CompletedHandler = value;
1050 _M_asyncInfo.Get()->Completed = ref new _CompletionHandlerType([&](_AsyncOperationType, Windows::Foundation::AsyncStatus status) {
1051 _M_CompletedHandler->Invoke(this, status);
1052 });
1053 }
1054 }
1055 };
1056
1060 template<typename _Result, typename _Progress>
1061 ref struct _IAsyncOperationWithProgressToAsyncOperationConverter sealed :
1062 _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,
1063 Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,
1064 _Result>
1065 {
1066 internal:
1067 _IAsyncOperationWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^ _Operation) :
1068 _AsyncInfoImpl<Windows::Foundation::IAsyncOperationWithProgress<_Result,_Progress>^,
1069 Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_Result,_Progress>,
1070 _Result>(_Operation) {}
1071
1072 public:
1073 virtual _Result GetResults() override { return _M_asyncInfo.Get()->GetResults(); }
1074 };
1075
1079 ref struct _IAsyncActionToAsyncOperationConverter sealed :
1080 _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,
1081 Windows::Foundation::AsyncActionCompletedHandler,
1082 details::_Unit_type>
1083 {
1084 internal:
1085 _IAsyncActionToAsyncOperationConverter(Windows::Foundation::IAsyncAction^ _Operation) :
1086 _AsyncInfoImpl<Windows::Foundation::IAsyncAction^,
1087 Windows::Foundation::AsyncActionCompletedHandler,
1088 details::_Unit_type>(_Operation) {}
1089
1090 public:
1091 virtual details::_Unit_type GetResults() override
1092 {
1093 // Invoke GetResults on the IAsyncAction to allow exceptions to be thrown to higher layers before returning a dummy value.
1094 _M_asyncInfo.Get()->GetResults();
1095 return details::_Unit_type();
1096 }
1097 };
1098
1102 template<typename _Progress>
1103 ref struct _IAsyncActionWithProgressToAsyncOperationConverter sealed :
1104 _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,
1105 Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,
1106 details::_Unit_type>
1107 {
1108 internal:
1109 _IAsyncActionWithProgressToAsyncOperationConverter(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ _Action) :
1110 _AsyncInfoImpl<Windows::Foundation::IAsyncActionWithProgress<_Progress>^,
1111 Windows::Foundation::AsyncActionWithProgressCompletedHandler<_Progress>,
1112 details::_Unit_type>(_Action) {}
1113 public:
1114 virtual details::_Unit_type GetResults() override
1115 {
1116 // Invoke GetResults on the IAsyncActionWithProgress to allow exceptions to be thrown before returning a dummy value.
1117 _M_asyncInfo.Get()->GetResults();
1118 return details::_Unit_type();
1119 }
1120 };
1121 #endif /* defined (__cplusplus_winrt) */
1122 } // namespace details
1123
1130
1132 {
1133 public:
1134
1151
1153 {
1154 #if defined (__cplusplus_winrt)
1155 // The callback context is created with the context set to CaptureDeferred and resolved when it is used in .then()
1156 return task_continuation_context(
true);
// sets it to deferred, is resolved in the constructor of _ContinuationTaskHandle
1157 #else /* defined (__cplusplus_winrt) */
1159 #endif /* defined (__cplusplus_winrt) */
1160 }
1161
1162 #if defined (__cplusplus_winrt)
1163
1178 {
1180 _Arbitrary._Resolve(false);
1181 return _Arbitrary;
1182 }
1183
1197
1198 static task_continuation_context use_current()
1199 {
1200 task_continuation_context _Current(true);
1201 _Current._Resolve(true);
1202 return _Current;
1203 }
1204 #endif /* defined (__cplusplus_winrt) */
1205
1206 private:
1207
1208 task_continuation_context(bool _DeferCapture = false) : details::_ContextCallback(_DeferCapture)
1209 {
1210 }
1211 };
1212
1213 class task_options;
1214 namespace details
1215 {
1217 {
1218 bool _M_hasPresetCreationCallstack;
1220
1222 {
1223 _M_hasPresetCreationCallstack = true;
1224 _M_presetCreationCallstack = _callstack;
1225 }
1227 {
1228 _M_hasPresetCreationCallstack = false;
1229 }
1230 };
1231
1234 }
1239 {
1240 public:
1241
1242
1250 _M_HasCancellationToken(false),
1251 _M_HasScheduler(false)
1252 {
1253 }
1254
1260 _M_CancellationToken(_Token),
1262 _M_HasCancellationToken(true),
1263 _M_HasScheduler(false)
1264 {
1265 }
1266
1273 _M_ContinuationContext(_ContinuationContext),
1274 _M_HasCancellationToken(false),
1275 _M_HasScheduler(false)
1276 {
1277 }
1278
1284 _M_CancellationToken(_Token),
1285 _M_ContinuationContext(_ContinuationContext),
1286 _M_HasCancellationToken(false),
1287 _M_HasScheduler(false)
1288 {
1289 }
1290
1294 template<typename _SchedType>
1296 : _M_Scheduler(std::move(_Scheduler)),
1299 _M_HasCancellationToken(false),
1300 _M_HasScheduler(true)
1301 {
1302 }
1303
1308 : _M_Scheduler(&_Scheduler),
1311 _M_HasCancellationToken(false),
1312 _M_HasScheduler(true)
1313 {
1314 }
1315
1320 : _M_Scheduler(std::move(_Scheduler)),
1323 _M_HasCancellationToken(false),
1324 _M_HasScheduler(true)
1325 {
1326 }
1327
1332 : _M_Scheduler(_TaskOptions.get_scheduler()),
1333 _M_CancellationToken(_TaskOptions.get_cancellation_token()),
1334 _M_ContinuationContext(_TaskOptions.get_continuation_context()),
1335 _M_HasCancellationToken(_TaskOptions.has_cancellation_token()),
1336 _M_HasScheduler(_TaskOptions.has_scheduler())
1337 {
1338 }
1339
1344 {
1345 _M_CancellationToken = _Token;
1346 _M_HasCancellationToken = true;
1347 }
1348
1353 {
1354 _M_ContinuationContext = _ContinuationContext;
1355 }
1356
1361 {
1362 return _M_HasCancellationToken;
1363 }
1364
1369 {
1370 return _M_CancellationToken;
1371 }
1372
1377 {
1378 return _M_ContinuationContext;
1379 }
1380
1385 {
1386 return _M_HasScheduler;
1387 }
1388
1393 {
1394 return _M_Scheduler;
1395 }
1396
1397 private:
1398
1402
1407 bool _M_HasCancellationToken;
1408 bool _M_HasScheduler;
1409 };
1410
1411 namespace details
1412 {
1413 inline _Internal_task_options & _get_internal_task_options(task_options &options)
1414 {
1415 return options._M_InternalTaskOptions;
1416 }
1417 inline const _Internal_task_options & _get_internal_task_options(const task_options &options)
1418 {
1419 return options._M_InternalTaskOptions;
1420 }
1421
1422 struct _Task_impl_base;
1424
1425 template<typename _ReturnType>
1427 {
1428 typedef std::shared_ptr<_Task_impl<_ReturnType>> _Type;
1430 };
1431
1433 typedef std::shared_ptr<_Task_impl_base> _Task_ptr_base;
1434
1435 // The weak-typed base task handler for continuation tasks.
1437 {
1440 bool _M_isTaskBasedContinuation;
1441
1442 // This field gives inlining scheduling policy for current chore.
1443 _TaskInliningMode_t _M_inliningMode;
1444
1445 virtual _Task_ptr_base _GetTaskImplBase() const = 0;
1446
1449 {
1450 }
1451
1453 };
1454
1455 #if _PPLTASK_ASYNC_LOGGING
1456 // GUID used for identifying causality logs from PPLTask
1457 const ::Platform::Guid _PPLTaskCausalityPlatformID(0x7A76B220, 0xA758, 0x4E6E, 0xB0, 0xE0, 0xD7, 0xC6, 0xD7, 0x4A, 0x88, 0xFE);
1458
1459 __declspec(selectany) volatile
long _isCausalitySupported = 0;
1460
1461 inline bool _IsCausalitySupported()
1462 {
1463 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
1464 if (_isCausalitySupported == 0)
1465 {
1466 long _causality = 1;
1467 OSVERSIONINFOEX _osvi = {};
1468 _osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1469
1470 // The Causality is supported on Windows version higher than Windows 8
1471 _osvi.dwMajorVersion = 6;
1472 _osvi.dwMinorVersion = 3;
1473
1474 DWORDLONG _conditionMask = 0;
1475 VER_SET_CONDITION( _conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
1476 VER_SET_CONDITION( _conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL );
1477
1478 if ( ::VerifyVersionInfo(&_osvi, VER_MAJORVERSION | VER_MINORVERSION, _conditionMask))
1479 {
1480 _causality = 2;
1481 }
1482
1483 _isCausalitySupported = _causality;
1484 return _causality == 2;
1485 }
1486
1487 return _isCausalitySupported == 2 ? true : false;
1488 #else
1489 return true;
1490 #endif
1491 }
1492
1493 // Stateful logger rests inside task_impl_base.
1494 struct _TaskEventLogger
1495 {
1496 _Task_impl_base *_M_task;
1497 bool _M_scheduled;
1498 bool _M_taskPostEventStarted;
1499
1500 // Log before scheduling task
1501 void _LogScheduleTask(bool _isContinuation)
1502 {
1503 if (details::_IsCausalitySupported())
1504 {
1505 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCreation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1506 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task),
1507 _isContinuation ? "pplx::PPLTask::ScheduleContinuationTask" : "pplx::PPLTask::ScheduleTask", 0);
1508 _M_scheduled = true;
1509 }
1510 }
1511
1512 // It will log the cancel event but not canceled state. _LogTaskCompleted will log the terminal state, which includes cancel state.
1513 void _LogCancelTask()
1514 {
1515 if (details::_IsCausalitySupported())
1516 {
1517 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationRelation(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Important, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1518 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalityRelation::Cancel);
1519
1520 }
1521 }
1522
1523 // Log when task reaches terminal state. Note: the task can reach a terminal state (by cancellation or exception) without having run
1524 void _LogTaskCompleted();
1525
1526 // Log when task body (which includes user lambda and other scheduling code) begin to run
1527 void _LogTaskExecutionStarted() { }
1528
1529 // Log when task body finish executing
1530 void _LogTaskExecutionCompleted()
1531 {
1532 if (_M_taskPostEventStarted && details::_IsCausalitySupported())
1533 {
1534 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1535 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
1536 }
1537 }
1538
1539 // Log right before user lambda being invoked
1540 void _LogWorkItemStarted()
1541 {
1542 if (details::_IsCausalitySupported())
1543 {
1544 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1545 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
1546 }
1547 }
1548
1549 // Log right after user lambda being invoked
1550 void _LogWorkItemCompleted()
1551 {
1552 if (details::_IsCausalitySupported())
1553 {
1554 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1555 ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::Execution);
1556
1557 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceSynchronousWorkStart(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
1558 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), ::Windows::Foundation::Diagnostics::CausalitySynchronousWork::CompletionNotification);
1559 _M_taskPostEventStarted = true;
1560 }
1561 }
1562
1563 _TaskEventLogger(_Task_impl_base *_task): _M_task(_task)
1564 {
1565 _M_scheduled = false;
1566 _M_taskPostEventStarted = false;
1567 }
1568 };
1569
1570 // Exception safe logger for user lambda
1571 struct _TaskWorkItemRAIILogger
1572 {
1573 _TaskEventLogger &_M_logger;
1574 _TaskWorkItemRAIILogger(_TaskEventLogger &_taskHandleLogger): _M_logger(_taskHandleLogger)
1575 {
1576 _M_logger._LogWorkItemStarted();
1577 }
1578
1579 ~_TaskWorkItemRAIILogger()
1580 {
1581 _M_logger._LogWorkItemCompleted();
1582 }
1583 _TaskWorkItemRAIILogger &operator =(const _TaskWorkItemRAIILogger &); // cannot be assigned
1584 };
1585
1586 #else
1587 inline void _LogCancelTask(_Task_impl_base *) {}
1589 {
1590 void _LogScheduleTask(bool) {}
1591 void _LogCancelTask() {}
1592 void _LogWorkItemStarted() {}
1593 void _LogWorkItemCompleted() {}
1594 void _LogTaskExecutionStarted() {}
1595 void _LogTaskExecutionCompleted() {}
1596 void _LogTaskCompleted() {}
1598 };
1600 {
1602 };
1603 #endif
1604
1620 template<typename _ReturnType, typename _DerivedTaskHandle, typename _BaseTaskHandle>
1622 {
1623 _PPLTaskHandle(
const typename _Task_ptr<_ReturnType>::_Type & _PTask) : _M_pTask(_PTask)
1624 {
1625 }
1626
1628 {
1629 // Here is the sink of all task completion code paths
1630 _M_pTask->_M_taskEventLogger._LogTaskCompleted();
1631 }
1632
1633 virtual void invoke() const
1634 {
1635 // All exceptions should be rethrown to finish cleanup of the task collection. They will be caught and handled
1636 // by the runtime.
1637 _ASSERTE((bool)_M_pTask);
1638 if (!_M_pTask->_TransitionedToStarted())
1639 {
1640 static_cast<const _DerivedTaskHandle *>(this)->_SyncCancelAndPropagateException();
1641 return;
1642 }
1643
1644 _M_pTask->_M_taskEventLogger._LogTaskExecutionStarted();
1645 try
1646 {
1647 // All derived task handle must implement this contract function.
1648 static_cast<const _DerivedTaskHandle *>(this)->_Perform();
1649 }
1651 {
1652 _M_pTask->_Cancel(true);
1653 }
1655 {
1656 _M_pTask->_Cancel(true);
1657 }
1658 #if defined (__cplusplus_winrt)
1659 catch(::Platform::Exception^ _E)
1660 {
1661 _M_pTask->_CancelWithException(_E);
1662 }
1663 #endif /* defined (__cplusplus_winrt) */
1664 catch(...)
1665 {
1666 _M_pTask->_CancelWithException(std::current_exception());
1667 }
1668 _M_pTask->_M_taskEventLogger._LogTaskExecutionCompleted();
1669 }
1670
1671 // Cast _M_pTask pointer to "type-less" _Task_impl_base pointer, which can be used in _ContinuationTaskHandleBase.
1672 // The return value should be automatically optimized by R-value ref.
1673 _Task_ptr_base _GetTaskImplBase() const
1674 {
1675 return _M_pTask;
1676 }
1677
1678 typename _Task_ptr<_ReturnType>::_Type _M_pTask;
1679 private:
1681 };
1682
1687
1689 {
1690 enum _TaskInternalState
1691 {
1692 // Tracks the state of the task, rather than the task collection on which the task is scheduled
1693 _Created,
1694 _Started,
1695 _PendingCancel,
1696 _Completed,
1697 _Canceled
1698 };
1699 // _M_taskEventLogger - 'this' : used in base member initializer list
1700 #if defined(_MSC_VER)
1701 #pragma warning(push)
1702 #pragma warning(disable: 4355)
1703 #endif
1705 : _M_TaskState(_Created),
1706 _M_fFromAsync(false), _M_fUnwrappedTask(false),
1707 _M_pRegistration(nullptr), _M_Continuations(nullptr), _M_TaskCollection(_Scheduler_arg),
1708 _M_taskEventLogger(this)
1709 {
1710 // Set cancelation token
1711 _M_pTokenState = _PTokenState;
1712 _ASSERTE(_M_pTokenState != nullptr);
1713 if (_M_pTokenState != _CancellationTokenState::_None())
1714 _M_pTokenState->_Reference();
1715 }
1716 #if defined(_MSC_VER)
1717 #pragma warning(pop)
1718 #endif
1719
1721 {
1722 _ASSERTE(_M_pTokenState != nullptr);
1723 if (_M_pTokenState != _CancellationTokenState::_None())
1724 {
1725 _M_pTokenState->_Release();
1726 }
1727 }
1728
1729 task_status _Wait()
1730 {
1731 bool _DoWait = true;
1732
1733 #if defined (__cplusplus_winrt)
1734 if (_IsNonBlockingThread())
1735 {
1736 // In order to prevent Windows Runtime STA threads from blocking the UI, calling task.wait() task.get() is illegal
1737 // if task has not been completed.
1738 if (!_IsCompleted() && !_IsCanceled())
1739 {
1741 }
1742 else
1743 {
1744 // Task Continuations are 'scheduled' *inside* the chore that is executing on the ancestors's task group. If a continuation
1745 // needs to be marshalled to a different apartment, instead of scheduling, we make a synchronous cross apartment COM
1746 // call to execute the continuation. If it then happens to do something which waits on the ancestor (say it calls .get(), which
1747 // task based continuations are wont to do), waiting on the task group results in on the chore that is making this
1748 // synchronous callback, which causes a deadlock. To avoid this, we test the state ancestor's event , and we will NOT wait on
1749 // if it has finished execution (which means now we are on the inline synchronous callback).
1750 _DoWait = false;
1751 }
1752 }
1753 #endif /* defined (__cplusplus_winrt) */
1754 if (_DoWait)
1755 {
1756 // If this task was created from a Windows Runtime async operation, do not attempt to inline it. The
1757 // async operation will take place on a thread in the appropriate apartment Simply wait for the completed
1758 // event to be set.
1759 if (_M_fFromAsync)
1760 {
1761 _M_TaskCollection._Wait();
1762 }
1763 else
1764 {
1765 // Wait on the task collection to complete. The task collection is guaranteed to still be
1766 // valid since the task must be still within scope so that the _Task_impl_base destructor
1767 // has not yet been called. This call to _Wait potentially inlines execution of work.
1768 try
1769 {
1770 // Invoking wait on a task collection resets the state of the task collection. This means that
1771 // if the task collection itself were canceled, or had encountered an exception, only the first
1772 // call to wait will receive this status. However, both cancellation and exceptions flowing through
1773 // tasks set state in the task impl itself.
1774
1775 // When it returns cancelled, either work chore or the cancel thread should already have set task's state
1776 // properly -- cancelled state or completed state (because there was no interruption point).
1777 // For tasks with unwrapped tasks, we should not change the state of current task, since the unwrapped task are still running.
1778 _M_TaskCollection._RunAndWait();
1779 }
1781 {
1782 // The _TaskCollection will never be an interruption point since it has a none token.
1783 _ASSERTE(false);
1784 }
1786 {
1787 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
1788 // must be called from code that is executed within the task (throwing it from parallel work created by and waited
1789 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
1790 // the exception and canceled the task. Swallow the exception here.
1791 _ASSERTE(_IsCanceled());
1792 }
1793 #if defined (__cplusplus_winrt)
1794 catch(::Platform::Exception^ _E)
1795 {
1796 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
1797 if(!_HasUserException())
1798 {
1799 _CancelWithException(_E);
1800 }
1801 // Rethrow will mark the exception as observed.
1802 _M_exceptionHolder->_RethrowUserException();
1803 }
1804 #endif /* defined (__cplusplus_winrt) */
1805 catch(...)
1806 {
1807 // Its possible the task body hasn't seen the exception, if so we need to cancel with exception here.
1808 if(!_HasUserException())
1809 {
1810 _CancelWithException(std::current_exception());
1811 }
1812 // Rethrow will mark the exception as observed.
1813 _M_exceptionHolder->_RethrowUserException();
1814 }
1815
1816 // If the lambda body for this task (executed or waited upon in _RunAndWait above) happened to return a task
1817 // which is to be unwrapped and plumbed to the output of this task, we must not only wait on the lambda body, we must
1818 // wait on the **INNER** body. It is in theory possible that we could inline such if we plumb a series of things through;
1819 // however, this takes the tact of simply waiting upon the completion signal.
1820 if (_M_fUnwrappedTask)
1821 {
1822 _M_TaskCollection._Wait();
1823 }
1824 }
1825 }
1826
1827 if (_HasUserException())
1828 {
1829 _M_exceptionHolder->_RethrowUserException();
1830 }
1831 else if (_IsCanceled())
1832 {
1834 }
1835 _ASSERTE(_IsCompleted());
1837 }
1838
1858 virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr<_ExceptionHolder>& _ExHolder) = 0;
1859
1860 bool _Cancel(bool _SynchronousCancel)
1861 {
1862 // Send in a dummy value for exception. It is not used when the first parameter is false.
1863 return _CancelAndRunContinuations(_SynchronousCancel, false, false, _M_exceptionHolder);
1864 }
1865
1866 bool _CancelWithExceptionHolder(const std::shared_ptr<_ExceptionHolder>& _ExHolder, bool _PropagatedFromAncestor)
1867 {
1868 // This task was canceled because an ancestor task encountered an exception.
1869 return _CancelAndRunContinuations(true, true, _PropagatedFromAncestor, _ExHolder);
1870 }
1871
1872 #if defined (__cplusplus_winrt)
1873 bool _CancelWithException(::Platform::Exception^ _Exception)
1874 {
1875 // This task was canceled because the task body encountered an exception.
1876 _ASSERTE(!_HasUserException());
1877 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
1878 }
1879 #endif /* defined (__cplusplus_winrt) */
1880
1881 bool _CancelWithException(const std::exception_ptr& _Exception)
1882 {
1883 // This task was canceled because the task body encountered an exception.
1884 _ASSERTE(!_HasUserException());
1885 return _CancelAndRunContinuations(true, true, false, std::make_shared<_ExceptionHolder>(_Exception, _GetTaskCreationCallstack()));
1886 }
1887
1888 void _RegisterCancellation(std::weak_ptr<_Task_impl_base> _WeakPtr)
1889 {
1890 _ASSERTE(details::_CancellationTokenState::_IsValid(_M_pTokenState));
1891
1892 auto _CancellationCallback = [_WeakPtr](){
1893 // Taking ownership of the task prevents dead lock during destruction
1894 // if the destructor waits for the cancellations to be finished
1895 auto _task = _WeakPtr.lock();
1896 if (_task != nullptr)
1897 _task->_Cancel(false);
1898 };
1899
1901 _M_pTokenState->_RegisterCallback(_M_pRegistration);
1902 }
1903
1904 void _DeregisterCancellation()
1905 {
1906 if (_M_pRegistration != nullptr)
1907 {
1908 _M_pTokenState->_DeregisterCallback(_M_pRegistration);
1909 _M_pRegistration->_Release();
1910 _M_pRegistration = nullptr;
1911 }
1912 }
1913
1914 bool _IsCreated()
1915 {
1916 return (_M_TaskState == _Created);
1917 }
1918
1919 bool _IsStarted()
1920 {
1921 return (_M_TaskState == _Started);
1922 }
1923
1924 bool _IsPendingCancel()
1925 {
1926 return (_M_TaskState == _PendingCancel);
1927 }
1928
1929 bool _IsCompleted()
1930 {
1931 return (_M_TaskState == _Completed);
1932 }
1933
1934 bool _IsCanceled()
1935 {
1936 return (_M_TaskState == _Canceled);
1937 }
1938
1939 bool _HasUserException()
1940 {
1941 return static_cast<bool>(_M_exceptionHolder);
1942 }
1943
1944 const std::shared_ptr<_ExceptionHolder>& _GetExceptionHolder()
1945 {
1946 _ASSERTE(_HasUserException());
1947 return _M_exceptionHolder;
1948 }
1949
1950 bool _IsApartmentAware()
1951 {
1952 return _M_fFromAsync;
1953 }
1954
1955 void _SetAsync(bool _Async = true)
1956 {
1957 _M_fFromAsync = _Async;
1958 }
1959
1961 {
1962 return _M_pTaskCreationCallstack;
1963 }
1964
1966 {
1967 _M_pTaskCreationCallstack = _Callstack;
1968 }
1969
1979 void _ScheduleTask(_UnrealizedChore_t * _PTaskHandle, _TaskInliningMode_t _InliningMode)
1980 {
1981 try
1982 {
1983 _M_TaskCollection._ScheduleTask(_PTaskHandle, _InliningMode);
1984 }
1986 {
1987 // task_canceled is a special exception thrown by cancel_current_task. The spec states that cancel_current_task
1988 // must be called from code that is executed within the task (throwing it from parallel work created by and waited
1989 // upon by the task is acceptable). We can safely assume that the task wrapper _PPLTaskHandle::operator() has seen
1990 // the exception and canceled the task. Swallow the exception here.
1991 _ASSERTE(_IsCanceled());
1992 }
1994 {
1995 // The _TaskCollection will never be an interruption point since it has a none token.
1996 _ASSERTE(false);
1997 }
1998 catch(...)
1999 {
2000 // The exception could have come from two places:
2001 // 1. From the chore body, so it already should have been caught and canceled.
2002 // In this case swallow the exception.
2003 // 2. From trying to actually schedule the task on the scheduler.
2004 // In this case cancel the task with the current exception, otherwise the
2005 // task will never be signaled leading to deadlock when waiting on the task.
2006 if (!_HasUserException())
2007 {
2008 _CancelWithException(std::current_exception());
2009 }
2010 }
2011 }
2012
2020
2022 {
2023 _Task_ptr_base _ImplBase = _PTaskHandle->_GetTaskImplBase();
2024 if (_IsCanceled() && !_PTaskHandle->_M_isTaskBasedContinuation)
2025 {
2026 if (_HasUserException())
2027 {
2028 // If the ancestor encountered an exception, transfer the exception to the continuation
2029 // This traverses down the tree to propagate the exception.
2030 _ImplBase->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
2031 }
2032 else
2033 {
2034 // If the ancestor was canceled, then your own execution should be canceled.
2035 // This traverses down the tree to cancel it.
2036 _ImplBase->_Cancel(true);
2037 }
2038 }
2039 else
2040 {
2041 // This can only run when the ancestor has completed or it's a task based continuation that fires when a task is canceled
2042 // (with or without a user exception).
2043 _ASSERTE(_IsCompleted() || _PTaskHandle->_M_isTaskBasedContinuation);
2044 _ASSERTE(!_ImplBase->_IsCanceled());
2045 return _ImplBase->_ScheduleContinuationTask(_PTaskHandle);
2046 }
2047
2048 // If the handle is not scheduled, we need to manually delete it.
2049 delete _PTaskHandle;
2050 }
2051
2052 // Schedule a continuation to run
2054 {
2055
2056 _M_taskEventLogger._LogScheduleTask(true);
2057 // Ensure that the continuation runs in proper context (this might be on a Concurrency Runtime thread or in a different Windows Runtime apartment)
2058 if (_PTaskHandle->_M_continuationContext._HasCapturedContext())
2059 {
2060 // For those continuations need to be scheduled inside captured context, we will try to apply automatic inlining to their inline modes,
2061 // if they haven't been specified as _ForceInline yet. This change will encourage those continuations to be executed inline so that reduce
2062 // the cost of marshaling.
2063 // For normal continuations we won't do any change here, and their inline policies are completely decided by ._ThenImpl method.
2064 if (_PTaskHandle->_M_inliningMode != details::_ForceInline)
2065 {
2066 _PTaskHandle->_M_inliningMode = details::_DefaultAutoInline;
2067 }
2068 _ScheduleFuncWithAutoInline([_PTaskHandle]() {
2069 // Note that we cannot directly capture "this" pointer, instead, we should use _TaskImplPtr, a shared_ptr to the _Task_impl_base.
2070 // Because "this" pointer will be invalid as soon as _PTaskHandle get deleted. _PTaskHandle will be deleted after being scheduled.
2071 auto _TaskImplPtr = _PTaskHandle->_GetTaskImplBase();
2072 if (details::_ContextCallback::_CaptureCurrent() == _PTaskHandle->_M_continuationContext)
2073 {
2074 _TaskImplPtr->_ScheduleTask(_PTaskHandle, details::_ForceInline);
2075 }
2076 else
2077 {
2078 //
2079 // It's entirely possible that the attempt to marshal the call into a differing context will fail. In this case, we need to handle
2080 // the exception and mark the continuation as canceled with the appropriate exception. There is one slight hitch to this:
2081 //
2082 // NOTE: COM's legacy behavior is to swallow SEH exceptions and marshal them back as HRESULTS. This will in effect turn an SEH into
2083 // a C++ exception that gets tagged on the task. One unfortunate result of this is that various pieces of the task infrastructure will
2084 // not be in a valid state after this in /EHsc (due to the lack of destructors running, etc...).
2085 //
2086 try
2087 {
2088 // Dev10 compiler needs this!
2089 auto _PTaskHandle1 = _PTaskHandle;
2090 _PTaskHandle->_M_continuationContext._CallInContext( [_PTaskHandle1, _TaskImplPtr](){
2091 _TaskImplPtr->_ScheduleTask(_PTaskHandle1, details::_ForceInline);
2092 });
2093 }
2094 #if defined (__cplusplus_winrt)
2095 catch(::Platform::Exception^ _E)
2096 {
2097 _TaskImplPtr->_CancelWithException(_E);
2098 }
2099 #endif /* defined (__cplusplus_winrt) */
2100 catch(...)
2101 {
2102 _TaskImplPtr->_CancelWithException(std::current_exception());
2103 }
2104 }
2105 }, _PTaskHandle->_M_inliningMode);
2106 }
2107 else
2108 {
2109 _ScheduleTask(_PTaskHandle, _PTaskHandle->_M_inliningMode);
2110 }
2111 }
2112
2123
2125 {
2126 enum { _Nothing, _Schedule, _Cancel, _CancelWithException } _Do = _Nothing;
2127
2128 // If the task has canceled, cancel the continuation. If the task has completed, execute the continuation right away.
2129 // Otherwise, add it to the list of pending continuations
2130 {
2132 if (_IsCompleted() || (_IsCanceled() && _PTaskHandle->_M_isTaskBasedContinuation))
2133 {
2134 _Do = _Schedule;
2135 }
2136 else if (_IsCanceled())
2137 {
2138 if (_HasUserException())
2139 {
2140 _Do = _CancelWithException;
2141 }
2142 else
2143 {
2144 _Do = _Cancel;
2145 }
2146 }
2147 else
2148 {
2149 // chain itself on the continuation chain.
2150 _PTaskHandle->_M_next = _M_Continuations;
2151 _M_Continuations = _PTaskHandle;
2152 }
2153 }
2154
2155 // Cancellation and execution of continuations should be performed after releasing the lock. Continuations off of
2156 // async tasks may execute inline.
2157 switch (_Do)
2158 {
2159 case _Schedule:
2160 {
2161 _PTaskHandle->_GetTaskImplBase()->_ScheduleContinuationTask(_PTaskHandle);
2162 break;
2163 }
2164 case _Cancel:
2165 {
2166 // If the ancestor was canceled, then your own execution should be canceled.
2167 // This traverses down the tree to cancel it.
2168 _PTaskHandle->_GetTaskImplBase()->_Cancel(true);
2169
2170 delete _PTaskHandle;
2171 break;
2172 }
2173 case _CancelWithException:
2174 {
2175 // If the ancestor encountered an exception, transfer the exception to the continuation
2176 // This traverses down the tree to propagate the exception.
2177 _PTaskHandle->_GetTaskImplBase()->_CancelWithExceptionHolder(_GetExceptionHolder(), true);
2178
2179 delete _PTaskHandle;
2180 break;
2181 }
2182 case _Nothing:
2183 default:
2184 // In this case, we have inserted continuation to continuation chain,
2185 // nothing more need to be done, just leave.
2186 break;
2187 }
2188 }
2189
2190 void _RunTaskContinuations()
2191 {
2192 // The link list can no longer be modified at this point,
2193 // since all following up continuations will be scheduled by themselves.
2194 _ContinuationList _Cur = _M_Continuations, _Next;
2195 _M_Continuations = nullptr;
2196 while (_Cur)
2197 {
2198 // Current node might be deleted after running,
2199 // so we must fetch the next first.
2200 _Next = _Cur->_M_next;
2201 _RunContinuation(_Cur);
2202 _Cur = _Next;
2203 }
2204 }
2205
2206 #if defined (__cplusplus_winrt)
2207 static bool _IsNonBlockingThread()
2208 {
2209 APTTYPE _AptType;
2210 APTTYPEQUALIFIER _AptTypeQualifier;
2211
2212 HRESULT hr = CoGetApartmentType(&_AptType, &_AptTypeQualifier);
2213 //
2214 // If it failed, it's not a Windows Runtime/COM initialized thread. This is not a failure.
2215 //
2216 if (SUCCEEDED(hr))
2217 {
2218 switch(_AptType)
2219 {
2220 case APTTYPE_STA:
2221 case APTTYPE_MAINSTA:
2222 return true;
2223 break;
2224 case APTTYPE_NA:
2225 switch(_AptTypeQualifier)
2226 {
2227 // A thread executing in a neutral apartment is either STA or MTA. To find out if this thread is allowed
2228 // to wait, we check the app qualifier. If it is an STA thread executing in a neutral apartment, waiting
2229 // is illegal, because the thread is responsible for pumping messages and waiting on a task could take the
2230 // thread out of circulation for a while.
2231 case APTTYPEQUALIFIER_NA_ON_STA:
2232 case APTTYPEQUALIFIER_NA_ON_MAINSTA:
2233 return true;
2234 break;
2235 }
2236 break;
2237 }
2238 }
2239
2240 #if _UITHREADCTXT_SUPPORT
2241 // This method is used to throw an exepection in _Wait() if called within STA. We
2242 // want the same behavior if _Wait is called on the UI thread.
2243 if (SUCCEEDED(CaptureUiThreadContext(nullptr)))
2244 {
2245 return true;
2246 }
2247 #endif /* _UITHREADCTXT_SUPPORT */
2248
2249 return false;
2250 }
2251
2252 template<typename _ReturnType, typename>
2253 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type & _OuterTask,
2254 Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
2255 {
2256 // This method is invoked either when a task is created from an existing async operation or
2257 // when a lambda that creates an async operation executes.
2258
2259 // If the outer task is pending cancel, cancel the async operation before setting the completed handler. The COM reference on
2260 // the IAsyncInfo object will be released when all ^references to the operation go out of scope.
2261
2262 // This assertion uses the existence of taskcollection to determine if the task was created from an event.
2263 // That is no longer valid as even tasks created from a user lambda could have no underlying taskcollection
2264 // when a custom scheduler is used.
2265 // _ASSERTE((!_OuterTask->_M_TaskCollection._IsCreated() || _OuterTask->_M_fUnwrappedTask) && !_OuterTask->_IsCanceled());
2266
2267 // Pass the shared_ptr by value into the lambda instead of using 'this'.
2268 _AsyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType>(
2269 [_OuterTask](Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _Operation, Windows::Foundation::AsyncStatus _Status) mutable
2270 {
2271 if (_Status == Windows::Foundation::AsyncStatus::Canceled)
2272 {
2273 _OuterTask->_Cancel(true);
2274 }
2275 else if (_Status == Windows::Foundation::AsyncStatus::Error)
2276 {
2277 _OuterTask->_CancelWithException(::Platform::Exception::ReCreateException(static_cast<int>(_Operation->ErrorCode.Value)));
2278 }
2279 else
2280 {
2281 _ASSERTE(_Status == Windows::Foundation::AsyncStatus::Completed);
2282 _OuterTask->_FinalizeAndRunContinuations(_Operation->GetResults());
2283 }
2284
2285 // Take away this shared pointers reference on the task instead of waiting for the delegate to be released. It could
2286 // be released on a different thread after a delay, and not releasing the reference here could cause the tasks to hold
2287 // on to resources longer than they should. As an example, without this reset, writing to a file followed by reading from
2288 // it using the Windows Runtime Async APIs causes a sharing violation.
2289 // Using const_cast is the workaround for failed mutable keywords
2290 const_cast<_Task_ptr<_ReturnType>::_Type &>(_OuterTask).reset();
2291 });
2292 _OuterTask->_SetUnwrappedAsyncOp(_AsyncOp);
2293 }
2294 #endif /* defined (__cplusplus_winrt) */
2295
2296 template<typename _ReturnType, typename _InternalReturnType>
2297 static void _AsyncInit(const typename _Task_ptr<_ReturnType>::_Type& _OuterTask, const task<_InternalReturnType> & _UnwrappedTask)
2298 {
2299 _ASSERTE(_OuterTask->_M_fUnwrappedTask && !_OuterTask->_IsCanceled());
2300
2301 //
2302 // We must ensure that continuations off _OuterTask (especially exception handling ones) continue to function in the
2303 // presence of an exception flowing out of the inner task _UnwrappedTask. This requires an exception handling continuation
2304 // off the inner task which does the appropriate funnelling to the outer one. We use _Then instead of then to prevent
2305 // the exception from being marked as observed by our internal continuation. This continuation must be scheduled regardless
2306 // of whether or not the _OuterTask task is canceled.
2307 //
2308 _UnwrappedTask._Then([_OuterTask] (task<_InternalReturnType> _AncestorTask) {
2309
2310 if (_AncestorTask._GetImpl()->_IsCompleted())
2311 {
2312 _OuterTask->_FinalizeAndRunContinuations(_AncestorTask._GetImpl()->_GetResult());
2313 }
2314 else
2315 {
2316 _ASSERTE(_AncestorTask._GetImpl()->_IsCanceled());
2317 if (_AncestorTask._GetImpl()->_HasUserException())
2318 {
2319 // Set _PropagatedFromAncestor to false, since _AncestorTask is not an ancestor of _UnwrappedTask.
2320 // Instead, it is the enclosing task.
2321 _OuterTask->_CancelWithExceptionHolder(_AncestorTask._GetImpl()->_GetExceptionHolder(), false);
2322 }
2323 else
2324 {
2325 _OuterTask->_Cancel(true);
2326 }
2327 }
2328 }, nullptr, details::_DefaultAutoInline);
2329
2330 }
2331
2332 scheduler_ptr _GetScheduler() const
2333 {
2334 return _M_TaskCollection._GetScheduler();
2335 }
2336
2337 // Tracks the internal state of the task
2338 volatile _TaskInternalState _M_TaskState;
2339 // 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
2340 // async operation or async action that is unwrapped by the runtime.
2341 bool _M_fFromAsync;
2342 // Set to true when a continuation unwraps a task or async operation.
2343 bool _M_fUnwrappedTask;
2344
2345 // 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.
2346 // The exception is 'observed' if the user invokes get()/wait() on any of the tasks that are sharing this exception holder. If the exception
2347 // is not observed by the time the internal object owned by the shared pointer destructs, the process will fail fast.
2348 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
2349
2350 ::pplx::extensibility::critical_section_t _M_ContinuationsCritSec;
2351
2352 // The cancellation token state.
2353 _CancellationTokenState * _M_pTokenState;
2354
2355 // The registration on the token.
2356 _CancellationTokenRegistration * _M_pRegistration;
2357
2358 typedef _ContinuationTaskHandleBase * _ContinuationList;
2359 _ContinuationList _M_Continuations;
2360
2361 // The async task collection wrapper
2363
2364 // Callstack for function call (constructor or .then) that created this task impl.
2365 _TaskCreationCallstack _M_pTaskCreationCallstack;
2366
2367 _TaskEventLogger _M_taskEventLogger;
2368 private:
2369 // Must not be copied by value:
2370 _Task_impl_base(const _Task_impl_base&);
2371 _Task_impl_base const & operator=(_Task_impl_base const&);
2372 };
2373
2374 #if _PPLTASK_ASYNC_LOGGING
2375 inline void _TaskEventLogger::_LogTaskCompleted()
2376 {
2377 if (_M_scheduled)
2378 {
2379 ::Windows::Foundation::AsyncStatus _State;
2380 if (_M_task->_IsCompleted())
2381 _State = ::Windows::Foundation::AsyncStatus::Completed;
2382 else if (_M_task->_HasUserException())
2383 _State = ::Windows::Foundation::AsyncStatus::Error;
2384 else
2385 _State = ::Windows::Foundation::AsyncStatus::Canceled;
2386
2387 if (details::_IsCausalitySupported())
2388 {
2389 ::Windows::Foundation::Diagnostics::AsyncCausalityTracer::TraceOperationCompletion(::Windows::Foundation::Diagnostics::CausalityTraceLevel::Required, ::Windows::Foundation::Diagnostics::CausalitySource::Library,
2390 _PPLTaskCausalityPlatformID, reinterpret_cast<unsigned long long>(_M_task), _State);
2391 }
2392 }
2393 }
2394 #endif
2395
2404
2405 template<typename _ReturnType>
2406 struct _Task_impl : public _Task_impl_base
2407 {
2408 #if defined (__cplusplus_winrt)
2409 typedef Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value> _AsyncOperationType;
2410 #endif // defined(__cplusplus_winrt)
2411 _Task_impl(_CancellationTokenState * _Ct, scheduler_ptr _Scheduler_arg)
2412 : _Task_impl_base(_Ct, _Scheduler_arg)
2413 {
2414 #if defined (__cplusplus_winrt)
2415 _M_unwrapped_async_op = nullptr;
2416 #endif /* defined (__cplusplus_winrt) */
2417 }
2418
2419 virtual ~_Task_impl()
2420 {
2421 // We must invoke _DeregisterCancellation in the derived class destructor. Calling it in the base class destructor could cause
2422 // a partially initialized _Task_impl to be in the list of registrations for a cancellation token.
2423 _DeregisterCancellation();
2424 }
2425
2426 virtual bool _CancelAndRunContinuations(
bool _SynchronousCancel,
bool _UserException,
bool _PropagatedFromAncestor,
const std::shared_ptr<_ExceptionHolder> & _ExceptionHolder_arg)
2427 {
2428 bool _RunContinuations = false;
2429 {
2431 if (_UserException)
2432 {
2433 _ASSERTE(_SynchronousCancel && !_IsCompleted());
2434 // If the state is _Canceled, the exception has to be coming from an ancestor.
2435 _ASSERTE(!_IsCanceled() || _PropagatedFromAncestor);
2436
2437 // We should not be canceled with an exception more than once.
2438 _ASSERTE(!_HasUserException());
2439
2440 // Mark _PropagatedFromAncestor as used.
2441 (void)_PropagatedFromAncestor;
2442
2443 if (_M_TaskState == _Canceled)
2444 {
2445 // If the task has finished cancelling there should not be any continuation records in the array.
2446 return false;
2447 }
2448 else
2449 {
2450 _ASSERTE(_M_TaskState != _Completed);
2451 _M_exceptionHolder = _ExceptionHolder_arg;
2452 }
2453 }
2454 else
2455 {
2456 // Completed is a non-cancellable state, and if this is an asynchronous cancel, we're unable to do better than the last async cancel
2457 // which is to say, cancellation is already initiated, so return early.
2458 if (_IsCompleted() || _IsCanceled() || (_IsPendingCancel() && !_SynchronousCancel))
2459 {
2460 _ASSERTE(!_IsCompleted() || !_HasUserException());
2461 return false;
2462 }
2463 _ASSERTE(!_SynchronousCancel || !_HasUserException());
2464 }
2465
2466 if (_SynchronousCancel)
2467 {
2468 // Be aware that this set must be done BEFORE _M_Scheduled being set, or race will happen between this and wait()
2469 _M_TaskState = _Canceled;
2470 // Cancellation completes the task, so all dependent tasks must be run to cancel them
2471 // They are canceled when they begin running (see _RunContinuation) and see that their
2472 // ancestor has been canceled.
2473 _RunContinuations = true;
2474 }
2475 else
2476 {
2477 _ASSERTE(!_UserException);
2478
2479 if (_IsStarted())
2480 {
2481 #if defined (__cplusplus_winrt)
2482 if (_M_unwrapped_async_op != nullptr)
2483 {
2484 // We will only try to cancel async operation but not unwrapped tasks, since unwrapped tasks cannot be canceled without its token.
2485 _M_unwrapped_async_op->Cancel();
2486 }
2487 #endif /* defined (__cplusplus_winrt) */
2488 _M_TaskCollection._Cancel();
2489 }
2490
2491 // The _M_TaskState variable transitions to _Canceled when cancellation is completed (the task is not executing user code anymore).
2492 // In the case of a synchronous cancel, this can happen immediately, whereas with an asynchronous cancel, the task has to move from
2493 // _Started to _PendingCancel before it can move to _Canceled when it is finished executing.
2494 _M_TaskState = _PendingCancel;
2495
2496 _M_taskEventLogger._LogCancelTask();
2497 }
2498
2499
2500 }
2501
2502 // Only execute continuations and mark the task as completed if we were able to move the task to the _Canceled state.
2503 if (_RunContinuations)
2504 {
2505 _M_TaskCollection._Complete();
2506
2507 if (_M_Continuations)
2508 {
2509 // Scheduling cancellation with automatic inlining.
2510 _ScheduleFuncWithAutoInline([=](){ _RunTaskContinuations(); }, details::_DefaultAutoInline);
2511 }
2512 }
2513 return true;
2514 }
2515
2516 void _FinalizeAndRunContinuations(_ReturnType _Result)
2517 {
2518 _M_Result.Set(_Result);
2519
2520 {
2521 //
2522 // Hold this lock to ensure continuations being concurrently either get added
2523 // to the _M_Continuations vector or wait for the result
2524 //
2526
2527 // A task could still be in the _Created state if it was created with a task_completion_event.
2528 // It could also be in the _Canceled state for the same reason.
2529 _ASSERTE(!_HasUserException() && !_IsCompleted());
2530 if (_IsCanceled())
2531 {
2532 return;
2533 }
2534
2535 // Always transition to "completed" state, even in the face of unacknowledged pending cancellation
2536 _M_TaskState = _Completed;
2537 }
2538 _M_TaskCollection._Complete();
2539 _RunTaskContinuations();
2540 }
2541
2542 //
2543 // This method is invoked when the starts executing. The task returns early if this method returns true.
2544 //
2545 bool _TransitionedToStarted()
2546 {
2548 // Canceled state could only result from antecedent task's canceled state, but that code path will not reach here.
2549 _ASSERTE(!_IsCanceled());
2550 if (_IsPendingCancel())
2551 return false;
2552
2553 _ASSERTE(_IsCreated());
2554 _M_TaskState = _Started;
2555 return true;
2556 }
2557
2558 #if defined (__cplusplus_winrt)
2559 void _SetUnwrappedAsyncOp(_AsyncOperationType^ _AsyncOp)
2560 {
2562 // Cancel the async operation if the task itself is canceled, since the thread that canceled the task missed it.
2563 if (_IsPendingCancel())
2564 {
2565 _ASSERTE(!_IsCanceled());
2566 _AsyncOp->Cancel();
2567 }
2568 else
2569 {
2570 _M_unwrapped_async_op = _AsyncOp;
2571 }
2572 }
2573 #endif /* defined (__cplusplus_winrt) */
2574
2575 // Return true if the task has reached a terminal state
2576 bool _IsDone()
2577 {
2578 return _IsCompleted() || _IsCanceled();
2579 }
2580
2581 _ReturnType _GetResult()
2582 {
2583 return _M_Result.Get();
2584 }
2585
2586 _ResultHolder<_ReturnType> _M_Result; // this means that the result type must have a public default ctor.
2587 #if defined (__cplusplus_winrt)
2588 _AsyncOperationType^ _M_unwrapped_async_op;
2589 #endif /* defined (__cplusplus_winrt) */
2590 };
2591
2592 template<typename _ResultType>
2594 {
2595 private:
2598
2599 public:
2600
2601 typedef std::vector<typename _Task_ptr<_ResultType>::_Type> _TaskList;
2602
2604 _M_fHasValue(false), _M_fIsCanceled(false)
2605 {
2606 }
2607
2608 bool _HasUserException()
2609 {
2610 return _M_exceptionHolder != nullptr;
2611 }
2612
2614 {
2615 for( auto _TaskIt = _M_tasks.begin(); _TaskIt != _M_tasks.end(); ++_TaskIt )
2616 {
2617 _ASSERTE(!_M_fHasValue && !_M_fIsCanceled);
2618 // Cancel the tasks since the event was never signaled or canceled.
2619 (*_TaskIt)->_Cancel(true);
2620 }
2621 }
2622
2623 // We need to protect the loop over the array, so concurrent_vector would not have helped
2624 _TaskList _M_tasks;
2625 ::pplx::extensibility::critical_section_t _M_taskListCritSec;
2627 std::shared_ptr<_ExceptionHolder> _M_exceptionHolder;
2628 bool _M_fHasValue;
2629 bool _M_fIsCanceled;
2630 };
2631
2632 // Utility method for dealing with void functions
2633 inline std::function<_Unit_type(void)> _MakeVoidToUnitFunc(const std::function<void(void)>& _Func)
2634 {
2635 return [=]() -> _Unit_type { _Func(); return _Unit_type(); };
2636 }
2637
2638 template <typename _Type>
2639 std::function<_Type(_Unit_type)> _MakeUnitToTFunc(const std::function<_Type(void)>& _Func)
2640 {
2641 return [=](_Unit_type) -> _Type { return _Func(); };
2642 }
2643
2644 template <typename _Type>
2645 std::function<_Unit_type(_Type)> _MakeTToUnitFunc(const std::function<void(_Type)>& _Func)
2646 {
2647 return [=](_Type t) -> _Unit_type { _Func(t); return _Unit_type(); };
2648 }
2649
2650 inline std::function<_Unit_type(_Unit_type)> _MakeUnitToUnitFunc(const std::function<void(void)>& _Func)
2651 {
2652 return [=](_Unit_type) -> _Unit_type { _Func(); return _Unit_type(); };
2653 }
2654 } // namespace details
2655
2672
2673 template<typename _ResultType>
2675 {
2676 public:
2680
2682 : _M_Impl(std::make_shared<details::_Task_completion_event_impl<_ResultType>>())
2683 {
2684 }
2685
2701
2702 bool set(_ResultType _Result)
const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2703 {
2704 // Subsequent sets are ignored. This makes races to set benign: the first setter wins and all others are ignored.
2705 if (_IsTriggered())
2706 {
2707 return false;
2708 }
2709
2710 _TaskList _Tasks;
2711 bool _RunContinuations = false;
2712 {
2714
2715 if (!_IsTriggered())
2716 {
2717 _M_Impl->_M_value.Set(_Result);
2718 _M_Impl->_M_fHasValue = true;
2719
2720 _Tasks.swap(_M_Impl->_M_tasks);
2721 _RunContinuations = true;
2722 }
2723 }
2724
2725 if (_RunContinuations)
2726 {
2727 for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )
2728 {
2729 // If current task was cancelled by a cancellation_token, it would be in cancel pending state.
2730 if ((*_TaskIt)->_IsPendingCancel())
2731 (*_TaskIt)->_Cancel(true);
2732 else
2733 {
2734 // Tasks created with task_completion_events can be marked as async, (we do this in when_any and when_all
2735 // if one of the tasks involved is an async task). Since continuations of async tasks can execute inline, we
2736 // need to run continuations after the lock is released.
2737 (*_TaskIt)->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
2738 }
2739 }
2740 if (_M_Impl->_HasUserException())
2741 {
2742 _M_Impl->_M_exceptionHolder.reset();
2743 }
2744 return true;
2745 }
2746
2747 return false;
2748 }
2749
2750 template<typename _E>
2751 __declspec(noinline)
// Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
2752 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2753 {
2754 // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2755 return _Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
2756 }
2757
2764
2765 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
2766 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2767 {
2768 // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2769 return _Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
2770 }
2771
2777 {
2778 // Cancel with the stored exception if one exists.
2779 return _CancelInternal();
2780 }
2781
2786 template<typename _ExHolderType>
2788 {
2789 bool _Canceled;
2790 if(_StoreException(_ExHolder, _SetExceptionAddressHint))
2791 {
2792 _Canceled = _CancelInternal();
2793 _ASSERTE(_Canceled);
2794 }
2795 else
2796 {
2797 _Canceled = false;
2798 }
2799 return _Canceled;
2800 }
2801
2807 template<typename _ExHolderType>
2809 {
2811 if (!_IsTriggered() && !_M_Impl->_HasUserException())
2812 {
2813 // Create the exception holder only if we have ensured there we will be successful in setting it onto the
2814 // task completion event. Failing to do so will result in an unobserved task exception.
2815 _M_Impl->_M_exceptionHolder = _ToExceptionHolder(_ExHolder, _SetExceptionAddressHint);
2816 return true;
2817 }
2818 return false;
2819 }
2820
2825 {
2826 return _M_Impl->_M_fHasValue || _M_Impl->_M_fIsCanceled;
2827 }
2828
2829 private:
2830
2831 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(
const std::shared_ptr<details::_ExceptionHolder>& _ExHolder,
const details::_TaskCreationCallstack&)
2832 {
2833 return _ExHolder;
2834 }
2835
2836 static std::shared_ptr<details::_ExceptionHolder> _ToExceptionHolder(std::exception_ptr _ExceptionPtr, const details::_TaskCreationCallstack &_SetExceptionAddressHint)
2837 {
2838 return std::make_shared<details::_ExceptionHolder>(_ExceptionPtr, _SetExceptionAddressHint);
2839 }
2840
2841
2842 template <typename T> friend class task; // task can register itself with the event by calling the private _RegisterTask
2843 template <typename T> friend class task_completion_event;
2844
2845 typedef typename details::_Task_completion_event_impl<_ResultType>::_TaskList _TaskList;
2846
2850 bool _CancelInternal() const
2851 {
2852 // Cancellation of task completion events is an internal only utility. Our usage is such that _CancelInternal
2853 // will never be invoked if the task completion event has been set.
2854 _ASSERTE(!_M_Impl->_M_fHasValue);
2855 if (_M_Impl->_M_fIsCanceled)
2856 {
2857 return false;
2858 }
2859
2860 _TaskList _Tasks;
2861 bool _Cancel = false;
2862 {
2864 _ASSERTE(!_M_Impl->_M_fHasValue);
2865 if (!_M_Impl->_M_fIsCanceled)
2866 {
2867 _M_Impl->_M_fIsCanceled = true;
2868 _Tasks.swap(_M_Impl->_M_tasks);
2869 _Cancel = true;
2870 }
2871 }
2872
2873 bool _UserException = _M_Impl->_HasUserException();
2874
2875 if (_Cancel)
2876 {
2877 for( auto _TaskIt = _Tasks.begin(); _TaskIt != _Tasks.end(); ++_TaskIt )
2878 {
2879 // Need to call this after the lock is released. See comments in set().
2880 if (_UserException)
2881 {
2882 (*_TaskIt)->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
2883 }
2884 else
2885 {
2886 (*_TaskIt)->_Cancel(true);
2887 }
2888 }
2889 }
2890 return _Cancel;
2891 }
2892
2897 void _RegisterTask(const typename details::_Task_ptr<_ResultType>::_Type & _TaskParam)
2898 {
2900
2901 //If an exception was already set on this event, then cancel the task with the stored exception.
2902 if(_M_Impl->_HasUserException())
2903 {
2904 _TaskParam->_CancelWithExceptionHolder(_M_Impl->_M_exceptionHolder, true);
2905 }
2906 else if (_M_Impl->_M_fHasValue)
2907 {
2908 _TaskParam->_FinalizeAndRunContinuations(_M_Impl->_M_value.Get());
2909 }
2910 else
2911 {
2912 _M_Impl->_M_tasks.push_back(_TaskParam);
2913 }
2914 }
2915
2916 std::shared_ptr<details::_Task_completion_event_impl<_ResultType>> _M_Impl;
2917 };
2918
2932
2933 template<>
2935 {
2936 public:
2949
2950 bool set() const
// 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2951 {
2952 return _M_unitEvent.set(details::_Unit_type());
2953 }
2954
2955 template<typename _E>
2956 __declspec(noinline)
// Ask for no inlining so that the _ReturnAddress intrinsic gives us the expected result
2957 bool set_exception(_E _Except) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2958 {
2959 return _M_unitEvent._Cancel(std::make_exception_ptr(_Except), _CAPTURE_CALLSTACK());
2960 }
2961
2968
2969 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK intrinsic gives us the expected result
2970 bool set_exception(std::exception_ptr _ExceptionPtr) const // 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2971 {
2972 // It is important that _CAPTURE_CALLSTACK() evaluate to the instruction after the call instruction for set_exception.
2973 return _M_unitEvent._Cancel(_ExceptionPtr, _CAPTURE_CALLSTACK());
2974 }
2975
2980 void _Cancel() const
// 'const' (even though it's not deep) allows to safely pass events by value into lambdas
2981 {
2982 _M_unitEvent._Cancel();
2983 }
2984
2989 void _Cancel(
const std::shared_ptr<details::_ExceptionHolder>& _ExHolder)
const
2990 {
2991 _M_unitEvent._Cancel(_ExHolder);
2992 }
2993
3000 {
3001 return _M_unitEvent._StoreException(_ExHolder);
3002 }
3003
3008 {
3009 return _M_unitEvent._IsTriggered();
3010 }
3011
3012 private:
3013 template <
typename T>
friend class task;
// task can register itself with the event by calling the private _RegisterTask
3014
3019 void _RegisterTask(details::_Task_ptr<details::_Unit_type>::_Type _TaskParam)
3020 {
3021 _M_unitEvent._RegisterTask(_TaskParam);
3022 }
3023
3024 // The void event contains an event a dummy type so common code can be used for events with void and non-void results.
3025 task_completion_event<details::_Unit_type> _M_unitEvent;
3026 };
3027
3028 namespace details
3029 {
3030 //
3031 // Compile-time validation helpers
3032 //
3033
3034 // Task constructor validation: issue helpful diagnostics for common user errors. Do not attempt full validation here.
3035 //
3036 // Anything callable is fine
3037 template<typename _ReturnType, typename _Ty>
3038 auto _IsValidTaskCtor(_Ty _Param, int,int,int,int) -> decltype(_Param(), std::true_type());
3039
3040 #if defined (__cplusplus_winrt)
3041 // Anything that has GetResults is fine: this covers all async operations
3042 template<typename _ReturnType, typename _Ty>
3043 auto _IsValidTaskCtor(_Ty _Param, int, int, int,...) -> decltype(_Param->GetResults(), std::true_type());
3044 #endif
3045
3046 // Allow parameters with set: this covers task_completion_event
3047 template<typename _ReturnType, typename _Ty>
3048 auto _IsValidTaskCtor(_Ty _Param, int, int, ...) -> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type());
3049
3050 template<typename _ReturnType, typename _Ty>
3051 auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type());
3052
3053 // All else is invalid
3054 template<typename _ReturnType, typename _Ty>
3055 std::false_type _IsValidTaskCtor(_Ty _Param, ...);
3056
3057 template<typename _ReturnType, typename _Ty>
3058 void _ValidateTaskConstructorArgs(_Ty _Param)
3059 {
3060 static_assert(std::is_same<decltype(_IsValidTaskCtor<_ReturnType>(_Param,0,0,0,0)),std::true_type>::value,
3061 #if defined (__cplusplus_winrt)
3062 "incorrect argument for task constructor; can be a callable object, an asynchronous operation, or a task_completion_event"
3063 #else /* defined (__cplusplus_winrt) */
3064 "incorrect argument for task constructor; can be a callable object or a task_completion_event"
3065 #endif /* defined (__cplusplus_winrt) */
3066 );
3067 #if defined (__cplusplus_winrt)
3068 static_assert(!(std::is_same<_Ty,_ReturnType>::value && details::_IsIAsyncInfo<_Ty>::_Value),
3069 "incorrect template argument for task; consider using the return type of the async operation");
3070 #endif /* defined (__cplusplus_winrt) */
3071 }
3072
3073 #if defined (__cplusplus_winrt)
3074 // Helpers for create_async validation
3075 //
3076 // A parameter lambda taking no arguments is valid
3077 template<typename _Ty>
3078 static auto _IsValidCreateAsync(_Ty _Param, int, int, int, int) -> decltype(_Param(), std::true_type());
3079
3080 // A parameter lambda taking an cancellation_token argument is valid
3081 template<typename _Ty>
3082 static auto _IsValidCreateAsync(_Ty _Param,
int,
int,
int, ...) -> decltype(_Param(
cancellation_token::none()), std::true_type());
3083
3084 // A parameter lambda taking a progress report argument is valid
3085 template<typename _Ty>
3086 static auto _IsValidCreateAsync(_Ty _Param, int, int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType()), std::true_type());
3087
3088 // A parameter lambda taking a progress report and a cancellation_token argument is valid
3089 template<typename _Ty>
3090 static auto _IsValidCreateAsync(_Ty _Param,
int, ...) -> decltype(_Param(details::_ProgressReporterCtorArgType(),
cancellation_token::none()), std::true_type());
3091
3092 // All else is invalid
3093 template<typename _Ty>
3094 static std::false_type _IsValidCreateAsync(_Ty _Param, ...);
3095 #endif /* defined (__cplusplus_winrt) */
3096 }
3101 template<typename _InpType, typename _OutType>
3103 {
3104 public:
3105 static auto _Perform(std::function<_OutType(_InpType)> _Func) -> decltype(_Func)
3106 {
3107 return _Func;
3108 }
3109 };
3110
3111 template<typename _OutType>
3113 {
3114 public:
3115 static auto _Perform(std::function<_OutType(void)> _Func) -> decltype(details::_MakeUnitToTFunc<_OutType>(_Func))
3116 {
3117 return details::_MakeUnitToTFunc<_OutType>(_Func);
3118 }
3119 };
3120
3121 template<typename _InType>
3123 {
3124 public:
3125 static auto _Perform(std::function<void(_InType)> _Func) -> decltype(details::_MakeTToUnitFunc<_InType>(_Func))
3126 {
3127 return details::_MakeTToUnitFunc<_InType>(_Func);
3128 }
3129 };
3130
3131 template<>
3133 {
3134 public:
3135 static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeUnitToUnitFunc(_Func))
3136 {
3137 return details::_MakeUnitToUnitFunc(_Func);
3138 }
3139 };
3140
3141 // 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
3142 // to substitute for void). This is to minimize the special handling required for 'void'.
3143 template<typename _RetType>
3145 {
3146 public:
3147 static auto _Perform(std::function<_RetType(void)> _Func) -> decltype(_Func)
3148 {
3149 return _Func;
3150 }
3151 };
3152
3153 template<>
3155 {
3156 public:
3157 static auto _Perform(std::function<void(void)> _Func) -> decltype(details::_MakeVoidToUnitFunc(_Func))
3158 {
3159 return details::_MakeVoidToUnitFunc(_Func);
3160 }
3161 };
3162
3176
3177 template<typename _ReturnType>
3179 {
3180 public:
3184
3186
3208
3210 {
3211 // The default constructor should create a task with a nullptr impl. This is a signal that the
3212 // task is not usable and should throw if any wait(), get() or then() APIs are used.
3213 }
3214
3249
3250 template<typename _Ty>
3251 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3252 explicit
task(_Ty _Param)
3253 {
3255 details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);
3256
3258 // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
3259 _SetTaskCreationCallstack(_CAPTURE_CALLSTACK());
3260
3261 _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
3262 }
3263
3297
3298 template<typename _Ty>
3299 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3301 {
3302 details::_ValidateTaskConstructorArgs<_ReturnType,_Ty>(_Param);
3303
3304 _CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
3305 // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
3306 _SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
3307
3308 _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
3309 }
3310
3335
3337
3362
3363 task(
task&& _Other): _M_Impl(std::move(_Other._M_Impl)) {}
3364
3375
3377 {
3378 if (this != &_Other)
3379 {
3380 _M_Impl = _Other._M_Impl;
3381 }
3382 return *this;
3383 }
3384
3395
3397 {
3398 if (this != &_Other)
3399 {
3400 _M_Impl = std::move(_Other._M_Impl);
3401 }
3402 return *this;
3403 }
3404
3424
3425 template<typename _Function>
3426 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3427 auto then(const _Function& _Func) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3428 {
3430 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3431 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3432 }
3433
3457
3458 template<typename _Function>
3459 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3460 auto then(const _Function& _Func,
task_options _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3461 {
3462 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3463 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3464 }
3465
3493
3494 template<typename _Function>
3495 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
3496 auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3497 {
3498 task_options _TaskOptions(_CancellationToken, _ContinuationContext);
3499 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
3500 return _ThenImpl<_ReturnType, _Function>(_Func, _TaskOptions);
3501 }
3502
3511
3513 {
3514 if (!_M_Impl)
3515 {
3516 throw invalid_operation(
"wait() cannot be called on a default constructed task.");
3517 }
3518
3519 return _M_Impl->_Wait();
3520 }
3521
3533
3534 _ReturnType
get()
const
3535 {
3536 if (!_M_Impl)
3537 {
3538 throw invalid_operation(
"get() cannot be called on a default constructed task.");
3539 }
3540
3542 {
3544 }
3545
3546 return _M_Impl->_GetResult();
3547 }
3548
3559 {
3560 if (!_M_Impl)
3561 {
3562 throw invalid_operation(
"is_done() cannot be called on a default constructed task.");
3563 }
3564
3565 return _M_Impl->_IsDone();
3566 }
3567
3575 {
3576 if (!_M_Impl)
3577 {
3578 throw invalid_operation(
"scheduler() cannot be called on a default constructed task.");
3579 }
3580
3581 return _M_Impl->_GetScheduler();
3582 }
3583
3590
3592 {
3593 if (!_M_Impl)
3594 {
3595 throw invalid_operation(
"is_apartment_aware() cannot be called on a default constructed task.");
3596 }
3597 return _M_Impl->_IsApartmentAware();
3598 }
3599
3606
3608 {
3609 return (_M_Impl == _Rhs._M_Impl);
3610 }
3611
3618
3620 {
3621 return !operator==(_Rhs);
3622 }
3623
3628 {
3629 _ASSERTE(_Ct != nullptr);
3631 if (_Ct != details::_CancellationTokenState::_None())
3632 {
3633 _M_Impl->_RegisterCancellation(_M_Impl);
3634 }
3635 }
3636
3640 const typename details::_Task_ptr<_ReturnType>::_Type &
_GetImpl()
const
3641 {
3642 return _M_Impl;
3643 }
3644
3648 void _SetImpl(
const typename details::_Task_ptr<_ReturnType>::_Type & _Impl)
3649 {
3650 _ASSERTE(!_M_Impl);
3651 _M_Impl = _Impl;
3652 }
3653
3657 void _SetImpl(
typename details::_Task_ptr<_ReturnType>::_Type && _Impl)
3658 {
3659 _ASSERTE(!_M_Impl);
3660 _M_Impl = std::move(_Impl);
3661 }
3662
3667 {
3668 _GetImpl()->_SetAsync(_Async);
3669 }
3670
3675 {
3676 _GetImpl()->_SetTaskCreationCallstack(_callstack);
3677 }
3678
3684 template<typename _Function>
3686 details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, _ReturnType>::_TaskOfType
3687 {
3688 // inherit from antecedent
3689 auto _Scheduler = _GetImpl()->_GetScheduler();
3690
3692 }
3693
3694 private:
3695 template <
typename T>
friend class task;
3696
3697
3698 // The task handle type used to construct an 'initial task' - a task with no dependents.
3699 template <typename _InternalReturnType, typename _Function, typename _TypeSelection>
3700 struct _InitialTaskHandle :
3701 details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>
3702 {
3703 _Function _M_function;
3704 _InitialTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _TaskImpl, const _Function & _func)
3705 : details::_PPLTaskHandle<_ReturnType, _InitialTaskHandle<_InternalReturnType, _Function, _TypeSelection>, details::_UnrealizedChore_t>::_PPLTaskHandle(_TaskImpl)
3706 , _M_function(_func)
3707 {
3708 }
3709
3710 virtual ~_InitialTaskHandle() {}
3711
3712 template <typename _Func>
3713 auto _LogWorkItemAndInvokeUserLambda(_Func && _func) const -> decltype(_func())
3714 {
3715 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
3716 CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);
3717 return _func();
3718 }
3719
3720 void _Perform() const
3721 {
3722 _Init(_TypeSelection());
3723 }
3724
3725 void _SyncCancelAndPropagateException() const
3726 {
3727 this->_M_pTask->_Cancel(true);
3728 }
3729
3730 //
3731 // Overload 0: returns _InternalReturnType
3732 //
3733 // This is the most basic task with no unwrapping
3734 //
3735 void _Init(details::_TypeSelectorNoAsync) const
3736 {
3737 this->_M_pTask->_FinalizeAndRunContinuations(_LogWorkItemAndInvokeUserLambda(_Init_func_transformer<_InternalReturnType>::_Perform(_M_function)));
3738 }
3739
3740 //
3741 // Overload 1: returns IAsyncOperation<_InternalReturnType>^ (only uder /ZW)
3742 // or
3743 // returns task<_InternalReturnType>
3744 //
3745 // This is task whose functor returns an async operation or a task which will be unwrapped for continuation
3746 // Depending on the output type, the right _AsyncInit gets invoked
3747 //
3748 void _Init(details::_TypeSelectorAsyncOperationOrTask) const
3749 {
3750 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, _LogWorkItemAndInvokeUserLambda(_M_function));
3751 }
3752
3753 #if defined (__cplusplus_winrt)
3754 //
3755 // Overload 2: returns IAsyncAction^
3756 //
3757 // This is task whose functor returns an async action which will be unwrapped for continuation
3758 //
3759 void _Init(details::_TypeSelectorAsyncAction) const
3760 {
3761 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask, ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function)));
3762 }
3763
3764 //
3765 // Overload 3: returns IAsyncOperationWithProgress<_InternalReturnType, _ProgressType>^
3766 //
3767 // This is task whose functor returns an async operation with progress which will be unwrapped for continuation
3768 //
3769 void _Init(details::_TypeSelectorAsyncOperationWithProgress) const
3770 {
3771 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
3772
3773 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,
3774 ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_InternalReturnType,_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));
3775 }
3776
3777 //
3778 // Overload 4: returns IAsyncActionWithProgress<_ProgressType>^
3779 //
3780 // This is task whose functor returns an async action with progress which will be unwrapped for continuation
3781 //
3782 void _Init(details::_TypeSelectorAsyncActionWithProgress) const
3783 {
3784 typedef details::_GetProgressType<decltype(_M_function())>::_Value _ProgressType;
3785
3786 details::_Task_impl_base::_AsyncInit<_ReturnType, _InternalReturnType>(this->_M_pTask,
3787 ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_LogWorkItemAndInvokeUserLambda(_M_function)));
3788 }
3789 #endif /* defined (__cplusplus_winrt) */
3790 };
3791
3792
3796 template <typename _InternalReturnType, typename _ContinuationReturnType, typename _Function, typename _IsTaskBased, typename _TypeSelection>
3797 struct _ContinuationTaskHandle :
3798 details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
3799 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
3800 {
3801 typedef typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type _NormalizedContinuationReturnType;
3802
3803 typename details::_Task_ptr<_ReturnType>::_Type _M_ancestorTaskImpl;
3804 _Function _M_function;
3805
3806 _ContinuationTaskHandle(const typename details::_Task_ptr<_ReturnType>::_Type & _AncestorImpl,
3807 const typename details::_Task_ptr<_NormalizedContinuationReturnType>::_Type & _ContinuationImpl,
3808 const _Function & _Func, const task_continuation_context & _Context, details::_TaskInliningMode_t _InliningMode)
3809 : details::_PPLTaskHandle<typename details::_NormalizeVoidToUnitType<_ContinuationReturnType>::_Type,
3810 _ContinuationTaskHandle<_InternalReturnType, _ContinuationReturnType, _Function, _IsTaskBased, _TypeSelection>, details::_ContinuationTaskHandleBase>
3811 ::_PPLTaskHandle(_ContinuationImpl)
3812 , _M_ancestorTaskImpl(_AncestorImpl)
3813 , _M_function(_Func)
3814 {
3815 this->_M_isTaskBasedContinuation = _IsTaskBased::value;
3816 this->_M_continuationContext = _Context;
3817 this->_M_continuationContext._Resolve(_AncestorImpl->_IsApartmentAware());
3818 this->_M_inliningMode = _InliningMode;
3819 }
3820
3821 virtual ~_ContinuationTaskHandle() {}
3822
3823 template <typename _Func, typename _Arg>
3824 auto _LogWorkItemAndInvokeUserLambda(_Func && _func, _Arg && _value) const -> decltype(_func(std::forward<_Arg>(_value)))
3825 {
3826 details::_TaskWorkItemRAIILogger _LogWorkItem(this->_M_pTask->_M_taskEventLogger);
3827 CASABLANCA_UNREFERENCED_PARAMETER(_LogWorkItem);
3828 return _func(std::forward<_Arg>(_value));
3829 }
3830
3831 void _Perform() const
3832 {
3833 _Continue(_IsTaskBased(), _TypeSelection());
3834 }
3835
3836 void _SyncCancelAndPropagateException() const
3837 {
3838 if (_M_ancestorTaskImpl->_HasUserException())
3839 {
3840 // If the ancestor encountered an exception, transfer the exception to the continuation
3841 // This traverses down the tree to propagate the exception.
3842 this->_M_pTask->_CancelWithExceptionHolder(_M_ancestorTaskImpl->_GetExceptionHolder(), true);
3843 }
3844 else
3845 {
3846 // If the ancestor was canceled, then your own execution should be canceled.
3847 // This traverses down the tree to cancel it.
3848 this->_M_pTask->_Cancel(true);
3849 }
3850 }
3851
3852 //
3853 // Overload 0-0: _InternalReturnType -> _TaskType
3854 //
3855 // This is a straight task continuation which simply invokes its target with the ancestor's completion argument
3856 //
3857 void _Continue(std::false_type, details::_TypeSelectorNoAsync) const
3858 {
3859 this->_M_pTask->_FinalizeAndRunContinuations(
3860 _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _ContinuationReturnType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult()));
3861 }
3862
3863 //
3864 // Overload 0-1: _InternalReturnType -> IAsyncOperation<_TaskType>^ (only uder /ZW)
3865 // or
3866 // _InternalReturnType -> task<_TaskType>
3867 //
3868 // This is a straight task continuation which returns an async operation or a task which will be unwrapped for continuation
3869 // Depending on the output type, the right _AsyncInit gets invoked
3870 //
3871 void _Continue(std::false_type, details::_TypeSelectorAsyncOperationOrTask) const
3872 {
3873 typedef typename details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3874
3875 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3876 this->_M_pTask,
3877 _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())
3878 );
3879 }
3880
3881 #if defined (__cplusplus_winrt)
3882 //
3883 // Overload 0-2: _InternalReturnType -> IAsyncAction^
3884 //
3885 // This is a straight task continuation which returns an async action which will be unwrapped for continuation
3886 //
3887 void _Continue(std::false_type, details::_TypeSelectorAsyncAction) const
3888 {
3889 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3890
3891 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3892 this->_M_pTask,
3893 ref new details::_IAsyncActionToAsyncOperationConverter(
3894 _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult())));
3895 }
3896
3897 //
3898 // Overload 0-3: _InternalReturnType -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^
3899 //
3900 // This is a straight task continuation which returns an async operation with progress which will be unwrapped for continuation
3901 //
3902 void _Continue(std::false_type, details::_TypeSelectorAsyncOperationWithProgress) const
3903 {
3904 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3905
3906 auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());
3907 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
3908
3909 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3910 this->_M_pTask,
3911 ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(_OpWithProgress));
3912 }
3913
3914 //
3915 // Overload 0-4: _InternalReturnType -> IAsyncActionWithProgress<_ProgressType>^
3916 //
3917 // This is a straight task continuation which returns an async action with progress which will be unwrapped for continuation
3918 //
3919 void _Continue(std::false_type, details::_TypeSelectorAsyncActionWithProgress) const
3920 {
3921 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType>::_FuncRetType _FuncOutputType;
3922
3923 auto _OpWithProgress = _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_InternalReturnType, _FuncOutputType>::_Perform(_M_function), _M_ancestorTaskImpl->_GetResult());
3924 typedef details::_GetProgressType<decltype(_OpWithProgress)>::_Value _ProgressType;
3925
3926 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(
3927 this->_M_pTask,
3928 ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(_OpWithProgress));
3929 }
3930
3931 #endif /* defined (__cplusplus_winrt) */
3932
3933 //
3934 // Overload 1-0: task<_InternalReturnType> -> _TaskType
3935 //
3936 // This is an exception handling type of continuation which takes the task rather than the task's result.
3937 //
3938 void _Continue(std::true_type, details::_TypeSelectorNoAsync) const
3939 {
3940 typedef task<_InternalReturnType> _FuncInputType;
3941 task<_InternalReturnType> _ResultTask;
3942 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3943 this->_M_pTask->_FinalizeAndRunContinuations(
3944 _LogWorkItemAndInvokeUserLambda(_Continuation_func_transformer<_FuncInputType, _ContinuationReturnType>::_Perform(_M_function), std::move(_ResultTask)));
3945 }
3946
3947 //
3948 // Overload 1-1: task<_InternalReturnType> -> IAsyncOperation<_TaskType>^
3949 // or
3950 // task<_TaskType>
3951 //
3952 // This is an exception handling type of continuation which takes the task rather than
3953 // the task's result. It also returns an async operation or a task which will be unwrapped
3954 // for continuation
3955 //
3956 void _Continue(std::true_type, details::_TypeSelectorAsyncOperationOrTask) const
3957 {
3958 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3959 task<_InternalReturnType> _ResultTask;
3960 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3961 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3962 _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask)));
3963 }
3964
3965 #if defined (__cplusplus_winrt)
3966
3967 //
3968 // Overload 1-2: task<_InternalReturnType> -> IAsyncAction^
3969 //
3970 // This is an exception handling type of continuation which takes the task rather than
3971 // the task's result. It also returns an async action which will be unwrapped for continuation
3972 //
3973 void _Continue(std::true_type, details::_TypeSelectorAsyncAction) const
3974 {
3975 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3976 task<_InternalReturnType> _ResultTask;
3977 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3978 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3979 ref new details::_IAsyncActionToAsyncOperationConverter(_LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
3980 }
3981
3982 //
3983 // Overload 1-3: task<_InternalReturnType> -> IAsyncOperationWithProgress<_TaskType, _ProgressType>^
3984 //
3985 // This is an exception handling type of continuation which takes the task rather than
3986 // the task's result. It also returns an async operation with progress which will be unwrapped
3987 // for continuation
3988 //
3989 void _Continue(std::true_type, details::_TypeSelectorAsyncOperationWithProgress) const
3990 {
3991 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
3992 task<_InternalReturnType> _ResultTask;
3993 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
3994
3995 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
3996
3997 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
3998 ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<_ContinuationReturnType, _ProgressType>(
3999 _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
4000 }
4001
4002 //
4003 // Overload 1-4: task<_InternalReturnType> -> IAsyncActionWithProgress<_ProgressType>^
4004 //
4005 // This is an exception handling type of continuation which takes the task rather than
4006 // the task's result. It also returns an async operation with progress which will be unwrapped
4007 // for continuation
4008 //
4009 void _Continue(std::true_type, details::_TypeSelectorAsyncActionWithProgress) const
4010 {
4011 // The continuation takes a parameter of type task<_Input>, which is the same as the ancestor task.
4012 task<_InternalReturnType> _ResultTask;
4013 _ResultTask._SetImpl(std::move(_M_ancestorTaskImpl));
4014
4015 typedef details::_GetProgressType<decltype(_M_function(_ResultTask))>::_Value _ProgressType;
4016
4017 details::_Task_impl_base::_AsyncInit<_NormalizedContinuationReturnType, _ContinuationReturnType>(this->_M_pTask,
4018 ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_ProgressType>(
4019 _LogWorkItemAndInvokeUserLambda(_M_function, std::move(_ResultTask))));
4020 }
4021 #endif /* defined (__cplusplus_winrt) */
4022 };
4023
4027 template<typename _InternalReturnType, typename _Function>
4028 void _TaskInitWithFunctor(const _Function& _Func)
4029 {
4030 typedef typename details::_InitFunctorTypeTraits<_InternalReturnType, decltype(_Func())> _Async_type_traits;
4031
4032 _M_Impl->_M_fFromAsync = _Async_type_traits::_IsAsyncTask;
4033 _M_Impl->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
4034 _M_Impl->_M_taskEventLogger._LogScheduleTask(false);
4035 _M_Impl->_ScheduleTask(new _InitialTaskHandle<_InternalReturnType, _Function, typename _Async_type_traits::_AsyncKind>(_GetImpl(), _Func), details::_NoInline);
4036 }
4037
4041 void _TaskInitNoFunctor(task_completion_event<_ReturnType>& _Event)
4042 {
4043 _Event._RegisterTask(_M_Impl);
4044 }
4045
4046 #if defined (__cplusplus_winrt)
4047 void _TaskInitAsyncOp(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
4051 {
4052 _M_Impl->_M_fFromAsync = true;
4053
4054 // Mark this task as started here since we can set the state in the constructor without acquiring a lock. Once _AsyncInit
4055 // returns a completion could execute concurrently and the task must be fully initialized before that happens.
4056 _M_Impl->_M_TaskState = details::_Task_impl_base::_Started;
4057 // Pass the shared pointer into _AsyncInit for storage in the Async Callback.
4058 details::_Task_impl_base::_AsyncInit<_ReturnType, _ReturnType>(_M_Impl, _AsyncOp);
4059 }
4060
4064 void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperation<typename details::_ValueTypeOrRefType<_ReturnType>::_Value>^ _AsyncOp)
4065 {
4066 _TaskInitAsyncOp(_AsyncOp);
4067 }
4068
4072 template<typename _Progress>
4073 void _TaskInitNoFunctor(Windows::Foundation::IAsyncOperationWithProgress<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>^ _AsyncOp)
4074 {
4075 _TaskInitAsyncOp(ref new details::_IAsyncOperationWithProgressToAsyncOperationConverter<typename details::_ValueTypeOrRefType<_ReturnType>::_Value, _Progress>(_AsyncOp));
4076 }
4077 #endif /* defined (__cplusplus_winrt) */
4078
4082 template<typename _Function>
4083 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
4084 {
4085 _TaskInitWithFunctor<_ReturnType, _Function>(_Func);
4086 }
4087
4091 template<typename _Ty>
4092 void _TaskInitMaybeFunctor(_Ty & _Param, std::false_type)
4093 {
4094 _TaskInitNoFunctor(_Param);
4095 }
4096
4097 template<typename _InternalReturnType, typename _Function>
4098 auto _ThenImpl(const _Function& _Func, const task_options& _TaskOptions) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
4099 {
4100 if (!_M_Impl)
4101 {
4102 throw invalid_operation("then() cannot be called on a default constructed task.");
4103 }
4104
4105 details::_CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
4106 auto _Scheduler = _TaskOptions.has_scheduler() ? _TaskOptions.get_scheduler() : _GetImpl()->_GetScheduler();
4107 auto _CreationStack = details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : details::_TaskCreationCallstack();
4108 return _ThenImpl<_InternalReturnType, _Function>(_Func, _PTokenState, _TaskOptions.get_continuation_context(), _Scheduler, _CreationStack);
4109 }
4110
4114 template<typename _InternalReturnType, typename _Function>
4115 auto _ThenImpl(const _Function& _Func, details::_CancellationTokenState *_PTokenState, const task_continuation_context& _ContinuationContext, scheduler_ptr _Scheduler, details::_TaskCreationCallstack _CreationStack,
4116 details::_TaskInliningMode_t _InliningMode = details::_NoInline) const -> typename details::_ContinuationTypeTraits<_Function, _InternalReturnType>::_TaskOfType
4117 {
4118 if (!_M_Impl)
4119 {
4120 throw invalid_operation("then() cannot be called on a default constructed task.");
4121 }
4122
4123 typedef details::_FunctionTypeTraits<_Function, _InternalReturnType> _Function_type_traits;
4124 typedef details::_TaskTypeTraits<typename _Function_type_traits::_FuncRetType> _Async_type_traits;
4125 typedef typename _Async_type_traits::_TaskRetType _TaskType;
4126
4127 //
4128 // 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
4129 // an exception handling continuation. In that case, we break the chain with a _None. That continuation is never canceled unless the user
4130 // explicitly passes the same token.
4131 //
4132 if (_PTokenState == nullptr)
4133 {
4134 if (_Function_type_traits::_Takes_task::value)
4135 {
4136 _PTokenState = details::_CancellationTokenState::_None();
4137 }
4138 else
4139 {
4140 _PTokenState = _GetImpl()->_M_pTokenState;
4141 }
4142 }
4143
4144 task<_TaskType> _ContinuationTask;
4145 _ContinuationTask._CreateImpl(_PTokenState, _Scheduler);
4146
4147 _ContinuationTask._GetImpl()->_M_fFromAsync = (_GetImpl()->_M_fFromAsync || _Async_type_traits::_IsAsyncTask);
4148 _ContinuationTask._GetImpl()->_M_fUnwrappedTask = _Async_type_traits::_IsUnwrappedTaskOrAsync;
4149 _ContinuationTask._SetTaskCreationCallstack(_CreationStack);
4150
4151 _GetImpl()->_ScheduleContinuation(new _ContinuationTaskHandle<_InternalReturnType, _TaskType, _Function, typename _Function_type_traits::_Takes_task, typename _Async_type_traits::_AsyncKind>(
4152 _GetImpl(), _ContinuationTask._GetImpl(), _Func, _ContinuationContext, _InliningMode));
4153
4154 return _ContinuationTask;
4155 }
4156
4157 // The underlying implementation for this task
4158 typename details::_Task_ptr<_ReturnType>::_Type _M_Impl;
4159 };
4160
4171
4172 template<>
4174 {
4175 public:
4179
4181
4203
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
4240
4241 template<typename _Ty>
4242 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4244 {
4245 details::_ValidateTaskConstructorArgs<void,_Ty>(_Param);
4246
4247 _M_unitTask._CreateImpl(_TaskOptions.get_cancellation_token()._GetImplValue(), _TaskOptions.get_scheduler());
4248 // Do not move the next line out of this function. It is important that _CAPTURE_CALLSTACK() evaluate to the the call site of the task constructor.
4249 _M_unitTask._SetTaskCreationCallstack(details::_get_internal_task_options(_TaskOptions)._M_hasPresetCreationCallstack ? details::_get_internal_task_options(_TaskOptions)._M_presetCreationCallstack : _CAPTURE_CALLSTACK());
4250
4251 _TaskInitMaybeFunctor(_Param, details::_IsCallable(_Param,0));
4252 }
4253
4278
4279 task(const task& _Other): _M_unitTask(_Other._M_unitTask){}
4280
4305
4306 task(task&& _Other) : _M_unitTask(std::move(_Other._M_unitTask)) {}
4307
4318
4319 task& operator=(const task& _Other)
4320 {
4321 if (this != &_Other)
4322 {
4323 _M_unitTask = _Other._M_unitTask;
4324 }
4325 return *this;
4326 }
4327
4338
4339 task& operator=(task&& _Other)
4340 {
4341 if (this != &_Other)
4342 {
4343 _M_unitTask = std::move(_Other._M_unitTask);
4344 }
4345 return *this;
4346 }
4347
4371
4372 template<typename _Function>
4373 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4374 auto then(const _Function& _Func, task_options _TaskOptions = task_options()) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4375 {
4376 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4377 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4378 }
4379
4407
4408 template<typename _Function>
4409 __declspec(noinline)
// Ask for no inlining so that the _CAPTURE_CALLSTACK gives us the expected result
4410 auto then(const _Function& _Func, cancellation_token _CancellationToken, task_continuation_context _ContinuationContext) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4411 {
4412 task_options _TaskOptions(_CancellationToken, _ContinuationContext);
4413 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4414 return _M_unitTask._ThenImpl<void, _Function>(_Func, _TaskOptions);
4415 }
4416
4425
4427 {
4428 return _M_unitTask.wait();
4429 }
4430
4439
4441 {
4442 _M_unitTask.get();
4443 }
4444
4455 {
4456 return _M_unitTask.is_done();
4457 }
4458
4466 {
4467 return _M_unitTask.scheduler();
4468 }
4469
4476
4478 {
4479 return _M_unitTask.is_apartment_aware();
4480 }
4481
4488
4490 {
4491 return (_M_unitTask == _Rhs._M_unitTask);
4492 }
4493
4500
4502 {
4503 return !operator==(_Rhs);
4504 }
4505
4510 {
4511 _M_unitTask._CreateImpl(_Ct, _Scheduler);
4512 }
4513
4517 const details::_Task_ptr<details::_Unit_type>::_Type &
_GetImpl()
const
4518 {
4519 return _M_unitTask._M_Impl;
4520 }
4521
4525 void _SetImpl(
const details::_Task_ptr<details::_Unit_type>::_Type & _Impl)
4526 {
4527 _M_unitTask._SetImpl(_Impl);
4528 }
4529
4533 void _SetImpl(details::_Task_ptr<details::_Unit_type>::_Type && _Impl)
4534 {
4535 _M_unitTask._SetImpl(std::move(_Impl));
4536 }
4537
4542 {
4543 _M_unitTask._SetAsync(_Async);
4544 }
4545
4550 {
4551 _M_unitTask._SetTaskCreationCallstack(_callstack);
4552 }
4553
4557 template<typename _Function>
4559 details::_TaskInliningMode_t _InliningMode = details::_ForceInline) const -> typename details::_ContinuationTypeTraits<_Function, void>::_TaskOfType
4560 {
4561 // inherit from antecedent
4562 auto _Scheduler = _GetImpl()->_GetScheduler();
4563
4565 }
4566
4567 private:
4568 template <
typename T>
friend class task;
4570
4575 {
4576 _M_unitTask._TaskInitNoFunctor(_Event._M_unitEvent);
4577 }
4578
4579 #if defined (__cplusplus_winrt)
4580 void _TaskInitNoFunctor(Windows::Foundation::IAsyncAction^ _AsyncAction)
4584 {
4585 _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionToAsyncOperationConverter(_AsyncAction));
4586 }
4587
4591 template<typename _P>
4592 void _TaskInitNoFunctor(Windows::Foundation::IAsyncActionWithProgress<_P>^ _AsyncActionWithProgress)
4593 {
4594 _M_unitTask._TaskInitAsyncOp(ref new details::_IAsyncActionWithProgressToAsyncOperationConverter<_P>(_AsyncActionWithProgress));
4595 }
4596 #endif /* defined (__cplusplus_winrt) */
4597
4601 template<typename _Function>
4602 void _TaskInitMaybeFunctor(_Function & _Func, std::true_type)
4603 {
4604 _M_unitTask._TaskInitWithFunctor<void, _Function>(_Func);
4605 }
4606
4610 template<typename _T>
4611 void _TaskInitMaybeFunctor(_T & _Param, std::false_type)
4612 {
4613 _TaskInitNoFunctor(_Param);
4614 }
4615
4616 // The void task contains a task of a dummy type so common code can be used for tasks with void and non-void results.
4617 task<details::_Unit_type> _M_unitTask;
4618 };
4619
4620 namespace details
4621 {
4625
4626 #if defined (__cplusplus_winrt)
4627 // Unwrap functions for asyncOperations
4628 template<typename _Ty>
4629 _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperation<_Ty>^);
4630
4631 void _GetUnwrappedType(Windows::Foundation::IAsyncAction^);
4632
4633 template<typename _Ty, typename _Progress>
4634 _Ty _GetUnwrappedType(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Progress>^);
4635
4636 template<typename _Progress>
4637 void _GetUnwrappedType(Windows::Foundation::IAsyncActionWithProgress<_Progress>^);
4638 #endif /* defined (__cplusplus_winrt) */
4639
4640 // Unwrap task<T>
4641 template<typename _Ty>
4642 _Ty _GetUnwrappedType(task<_Ty>);
4643
4644 // Unwrap all supportted types
4645 template<typename _Ty>
4646 auto _GetUnwrappedReturnType(_Ty _Arg, int) -> decltype(_GetUnwrappedType(_Arg));
4647 // fallback
4648 template<typename _Ty>
4649 _Ty _GetUnwrappedReturnType(_Ty, ...);
4650
4656
4657 // Non-Callable
4658 template<typename _Ty>
4659 _Ty _GetTaskType(task_completion_event<_Ty>, std::false_type);
4660
4661 // Non-Callable
4662 template<typename _Ty>
4663 auto _GetTaskType(_Ty _NonFunc, std::false_type) -> decltype(_GetUnwrappedType(_NonFunc));
4664
4665 // Callable
4666 template<typename _Ty>
4667 auto _GetTaskType(_Ty _Func, std::true_type) -> decltype(_GetUnwrappedReturnType(_Func(), 0));
4668
4669 // Special callable returns void
4670 void _GetTaskType(std::function<void()>, std::true_type);
4672
4673 template<typename _Ty>
4674 auto _FilterValidTaskType(_Ty _Param, int) -> decltype(_GetTaskType(_Param, _IsCallable(_Param, 0)));
4675
4676 template<typename _Ty>
4677 _BadArgType _FilterValidTaskType(_Ty _Param, ...);
4678
4679 template<typename _Ty>
4681 {
4682 typedef decltype(_FilterValidTaskType(stdx::declval<_Ty>(), 0)) _Type;
4683 };
4684 } // namespace details
4685
4713
4714 template<typename _Ty>
4716 auto create_task(_Ty _Param, task_options _TaskOptions = task_options()) ->
task<typename details::_TaskTypeFromParam<_Ty>::_Type>
4717 {
4719 #if defined (__cplusplus_winrt)
4720 "incorrect argument for create_task; can be a callable object, an asynchronous operation, or a task_completion_event"
4721 #else /* defined (__cplusplus_winrt) */
4722 "incorrect argument for create_task; can be a callable object or a task_completion_event"
4723 #endif /* defined (__cplusplus_winrt) */
4724 );
4725 details::_get_internal_task_options(_TaskOptions)._set_creation_callstack(_CAPTURE_CALLSTACK());
4727 return _CreatedTask;
4728 }
4729
4760
4761 template<typename _ReturnType>
4763 task<_ReturnType> create_task(const task<_ReturnType>& _Task)
4764 {
4765 task<_ReturnType> _CreatedTask(_Task);
4766 return _CreatedTask;
4767 }
4768
4769 #if defined (__cplusplus_winrt)
4770 namespace details
4771 {
4772 template<typename _T>
4773 task<_T> _To_task_helper(Windows::Foundation::IAsyncOperation<_T>^ op)
4774 {
4775 return task<_T>(op);
4776 }
4777
4778 template<typename _T, typename _Progress>
4779 task<_T> _To_task_helper(Windows::Foundation::IAsyncOperationWithProgress<_T, _Progress>^ op)
4780 {
4781 return task<_T>(op);
4782 }
4783
4784 inline task<void> _To_task_helper(Windows::Foundation::IAsyncAction^ op)
4785 {
4786 return task<void>(op);
4787 }
4788
4789 template<typename _Progress>
4790 task<void> _To_task_helper(Windows::Foundation::IAsyncActionWithProgress<_Progress>^ op)
4791 {
4792 return task<void>(op);
4793 }
4794
4795 template<typename _ProgressType>
4796 class _ProgressDispatcherBase
4797 {
4798 public:
4799
4800 virtual ~_ProgressDispatcherBase()
4801 {
4802 }
4803
4804 virtual void _Report(const _ProgressType& _Val) = 0;
4805 };
4806
4807 template<typename _ProgressType, typename _ClassPtrType>
4808 class _ProgressDispatcher : public _ProgressDispatcherBase<_ProgressType>
4809 {
4810 public:
4811
4812 virtual ~_ProgressDispatcher()
4813 {
4814 }
4815
4816 _ProgressDispatcher(_ClassPtrType _Ptr) : _M_ptr(_Ptr)
4817 {
4818 }
4819
4820 virtual void _Report(const _ProgressType& _Val)
4821 {
4822 _M_ptr->_FireProgress(_Val);
4823 }
4824
4825 private:
4826
4827 _ClassPtrType _M_ptr;
4828 };
4829 class _ProgressReporterCtorArgType{};
4830 } // namespace details
4831
4843
4844 template<typename _ProgressType>
4845 class progress_reporter
4846 {
4847 typedef std::shared_ptr<details::_ProgressDispatcherBase<_ProgressType>> _PtrType;
4848
4849 public:
4850
4857
4858 void report(const _ProgressType& _Val) const
4859 {
4860 _M_dispatcher->_Report(_Val);
4861 }
4862
4863 template<typename _ClassPtrType>
4864 static progress_reporter _CreateReporter(_ClassPtrType _Ptr)
4865 {
4866 progress_reporter _Reporter;
4867 details::_ProgressDispatcherBase<_ProgressType> *_PDispatcher = new details::_ProgressDispatcher<_ProgressType, _ClassPtrType>(_Ptr);
4868 _Reporter._M_dispatcher = _PtrType(_PDispatcher);
4869 return _Reporter;
4870 }
4871 progress_reporter() {}
4872
4873 private:
4874 progress_reporter(details::_ProgressReporterCtorArgType);
4875
4876 _PtrType _M_dispatcher;
4877 };
4878
4879 namespace details
4880 {
4881 //
4882 // maps internal definitions for AsyncStatus and defines states that are not client visible
4883 //
4884 enum _AsyncStatusInternal
4885 {
4886 _AsyncCreated = -1, // externally invisible
4887 // client visible states (must match AsyncStatus exactly)
4888 _AsyncStarted = 0, // Windows::Foundation::AsyncStatus::Started,
4889 _AsyncCompleted = 1, // Windows::Foundation::AsyncStatus::Completed,
4890 _AsyncCanceled = 2, // Windows::Foundation::AsyncStatus::Canceled,
4891 _AsyncError = 3, // Windows::Foundation::AsyncStatus::Error,
4892 // non-client visible internal states
4893 _AsyncCancelPending,
4894 _AsyncClosed,
4895 _AsyncUndefined
4896 };
4897
4898 //
4899 // designates whether the "GetResults" method returns a single result (after complete fires) or multiple results
4900 // (which are progressively consumable between Start state and before Close is called)
4901 //
4902 enum _AsyncResultType
4903 {
4904 SingleResult = 0x0001,
4905 MultipleResults = 0x0002
4906 };
4907
4908 // ***************************************************************************
4909 // Template type traits and helpers for async production APIs:
4910 //
4911
4912 struct _ZeroArgumentFunctor { };
4913 struct _OneArgumentFunctor { };
4914 struct _TwoArgumentFunctor { };
4915
4916 // ****************************************
4917 // CLASS TYPES:
4918
4919 // ********************
4920 // TWO ARGUMENTS:
4921
4922 // non-void arg:
4923 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4924 _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4925
4926 // non-void arg:
4927 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4928 _Arg2 _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4929
4930 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4931 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4932
4933 template<typename _Class, typename _ReturnType, typename _Arg1, typename _Arg2>
4934 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1, _Arg2) const);
4935
4936 // ********************
4937 // ONE ARGUMENT:
4938
4939 // non-void arg:
4940 template<typename _Class, typename _ReturnType, typename _Arg1>
4941 _Arg1 _Arg1ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4942
4943 // non-void arg:
4944 template<typename _Class, typename _ReturnType, typename _Arg1>
4945 void _Arg2ClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4946
4947 template<typename _Class, typename _ReturnType, typename _Arg1>
4948 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)(_Arg1) const);
4949
4950 template<typename _Class, typename _ReturnType, typename _Arg1>
4951 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)(_Arg1) const);
4952
4953 // ********************
4954 // ZERO ARGUMENT:
4955
4956 // void arg:
4957 template<typename _Class, typename _ReturnType>
4958 void _Arg1ClassHelperThunk(_ReturnType (_Class::*)() const);
4959
4960 // void arg:
4961 template<typename _Class, typename _ReturnType>
4962 void _Arg2ClassHelperThunk(_ReturnType (_Class::*)() const);
4963
4964 // void arg:
4965 template<typename _Class, typename _ReturnType>
4966 _ReturnType _ReturnTypeClassHelperThunk(_ReturnType (_Class::*)() const);
4967
4968 template<typename _Class, typename _ReturnType>
4969 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType (_Class::*)() const);
4970
4971 // ****************************************
4972 // POINTER TYPES:
4973
4974 // ********************
4975 // TWO ARGUMENTS:
4976
4977 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4978 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4979
4980 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4981 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4982
4983 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4984 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4985
4986 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4987 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1, _Arg2));
4988
4989 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4990 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4991
4992 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4993 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4994
4995 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4996 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1, _Arg2));
4997
4998 template<typename _ReturnType, typename _Arg1, typename _Arg2>
4999 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1, _Arg2));
5000
5001 template<typename _ReturnType, typename _Arg1, typename _Arg2>
5002 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5003
5004 template<typename _ReturnType, typename _Arg1, typename _Arg2>
5005 _Arg2 _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5006
5007 template<typename _ReturnType, typename _Arg1, typename _Arg2>
5008 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5009
5010 template<typename _ReturnType, typename _Arg1, typename _Arg2>
5011 _TwoArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1, _Arg2));
5012
5013 // ********************
5014 // ONE ARGUMENT:
5015
5016 template<typename _ReturnType, typename _Arg1>
5017 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5018
5019 template<typename _ReturnType, typename _Arg1>
5020 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5021
5022 template<typename _ReturnType, typename _Arg1>
5023 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)(_Arg1));
5024
5025 template<typename _ReturnType, typename _Arg1>
5026 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)(_Arg1));
5027
5028 template<typename _ReturnType, typename _Arg1>
5029 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5030
5031 template<typename _ReturnType, typename _Arg1>
5032 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5033
5034 template<typename _ReturnType, typename _Arg1>
5035 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)(_Arg1));
5036
5037 template<typename _ReturnType, typename _Arg1>
5038 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)(_Arg1));
5039
5040 template<typename _ReturnType, typename _Arg1>
5041 _Arg1 _Arg1PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5042
5043 template<typename _ReturnType, typename _Arg1>
5044 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5045
5046 template<typename _ReturnType, typename _Arg1>
5047 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)(_Arg1));
5048
5049 template<typename _ReturnType, typename _Arg1>
5050 _OneArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)(_Arg1));
5051
5052 // ********************
5053 // ZERO ARGUMENT:
5054
5055 template<typename _ReturnType>
5056 void _Arg1PFNHelperThunk(_ReturnType(__cdecl *)());
5057
5058 template<typename _ReturnType>
5059 void _Arg2PFNHelperThunk(_ReturnType(__cdecl *)());
5060
5061 template<typename _ReturnType>
5062 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__cdecl *)());
5063
5064 template<typename _ReturnType>
5065 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__cdecl *)());
5066
5067 template<typename _ReturnType>
5068 void _Arg1PFNHelperThunk(_ReturnType(__stdcall *)());
5069
5070 template<typename _ReturnType>
5071 void _Arg2PFNHelperThunk(_ReturnType(__stdcall *)());
5072
5073 template<typename _ReturnType>
5074 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__stdcall *)());
5075
5076 template<typename _ReturnType>
5077 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__stdcall *)());
5078
5079 template<typename _ReturnType>
5080 void _Arg1PFNHelperThunk(_ReturnType(__fastcall *)());
5081
5082 template<typename _ReturnType>
5083 void _Arg2PFNHelperThunk(_ReturnType(__fastcall *)());
5084
5085 template<typename _ReturnType>
5086 _ReturnType _ReturnTypePFNHelperThunk(_ReturnType(__fastcall *)());
5087
5088 template<typename _ReturnType>
5089 _ZeroArgumentFunctor _ArgumentCountHelper(_ReturnType(__fastcall *)());
5090
5091 template<typename _T>
5092 struct _FunctorArguments
5093 {
5094 static const size_t _Count = 0;
5095 };
5096
5097 template<>
5098 struct _FunctorArguments<_OneArgumentFunctor>
5099 {
5100 static const size_t _Count = 1;
5101 };
5102
5103 template<>
5104 struct _FunctorArguments<_TwoArgumentFunctor>
5105 {
5106 static const size_t _Count = 2;
5107 };
5108
5109 template<typename _T>
5110 struct _FunctorTypeTraits
5111 {
5112 typedef decltype(_ArgumentCountHelper(&(_T::operator()))) _ArgumentCountType;
5113 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
5114
5115 typedef decltype(_ReturnTypeClassHelperThunk(&(_T::operator()))) _ReturnType;
5116 typedef decltype(_Arg1ClassHelperThunk(&(_T::operator()))) _Argument1Type;
5117 typedef decltype(_Arg2ClassHelperThunk(&(_T::operator()))) _Argument2Type;
5118 };
5119
5120 template<typename _T>
5121 struct _FunctorTypeTraits<_T *>
5122 {
5123 typedef decltype(_ArgumentCountHelper(stdx::declval<_T*>())) _ArgumentCountType;
5124 static const size_t _ArgumentCount = _FunctorArguments<_ArgumentCountType>::_Count;
5125
5126 typedef decltype(_ReturnTypePFNHelperThunk(
stdx::declval<_T*>())) _ReturnType;
5127 typedef decltype(_Arg1PFNHelperThunk(
stdx::declval<_T*>())) _Argument1Type;
5128 typedef decltype(_Arg2PFNHelperThunk(
stdx::declval<_T*>())) _Argument2Type;
5129 };
5130
5131 template<typename _T>
5132 struct _ProgressTypeTraits
5133 {
5134 static const bool _TakesProgress = false;
5135 typedef void _ProgressType;
5136 };
5137
5138 template<typename _T>
5139 struct _ProgressTypeTraits<progress_reporter<_T>>
5140 {
5141 static const bool _TakesProgress = true;
5142 typedef typename _T _ProgressType;
5143 };
5144
5145
5146 template<typename _T, size_t count = _FunctorTypeTraits<_T>::_ArgumentCount>
5147 struct _CAFunctorOptions
5148 {
5149 static const bool _TakesProgress = false;
5150 static const bool _TakesToken = false;
5151 typedef void _ProgressType;
5152 };
5153
5154 template<typename _T>
5155 struct _CAFunctorOptions<_T, 1>
5156 {
5157 private:
5158
5159 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
5160
5161 public:
5162
5163 static const bool _TakesProgress = _ProgressTypeTraits<_Argument1Type>::_TakesProgress;
5164 static const bool _TakesToken = !_TakesProgress;
5165 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
5166 };
5167
5168 template<typename _T>
5169 struct _CAFunctorOptions<_T, 2>
5170 {
5171 private:
5172
5173 typedef typename _FunctorTypeTraits<_T>::_Argument1Type _Argument1Type;
5174
5175 public:
5176
5177 static const bool _TakesProgress = true;
5178 static const bool _TakesToken = true;
5179 typedef typename _ProgressTypeTraits<_Argument1Type>::_ProgressType _ProgressType;
5180 };
5181
5182 ref class _Zip
5183 {
5184 };
5185
5186 // ***************************************************************************
5187 // Async Operation Task Generators
5188 //
5189
5190 //
5191 // Functor returns an IAsyncInfo - result needs to be wrapped in a task:
5192 //
5193 template<typename _AsyncSelector, typename _ReturnType>
5194 struct _SelectorTaskGenerator
5195 {
5196 template<typename _Function>
5197 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5198 {
5199 task_options _taskOptinos(_Cts.get_token());
5200 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5201 return task<_ReturnType>(_Func(), _taskOptinos);
5202 }
5203
5204 template<typename _Function>
5205 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5206 {
5207 task_options _taskOptinos(_Cts.get_token());
5208 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5209 return task<_ReturnType>(_Func(_Cts.get_token()), _taskOptinos);
5210 }
5211
5212 template<typename _Function, typename _ProgressObject>
5213 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5214 {
5215 task_options _taskOptinos(_Cts.get_token());
5216 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5217 return task<_ReturnType>(_Func(_Progress), _taskOptinos);
5218 }
5219
5220 template<typename _Function, typename _ProgressObject>
5221 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5222 {
5223 task_options _taskOptinos(_Cts.get_token());
5224 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5225 return task<_ReturnType>(_Func(_Progress, _Cts.get_token()), _taskOptinos);
5226 }
5227 };
5228
5229 template<typename _AsyncSelector>
5230 struct _SelectorTaskGenerator<_AsyncSelector, void>
5231 {
5232 template<typename _Function>
5233 static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5234 {
5235 task_options _taskOptinos(_Cts.get_token());
5236 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5237 return task<void>(_Func(), _taskOptinos);
5238 }
5239
5240 template<typename _Function>
5241 static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5242 {
5243 task_options _taskOptinos(_Cts.get_token());
5244 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5245 return task<void>(_Func(_Cts.get_token()), _taskOptinos);
5246 }
5247
5248 template<typename _Function, typename _ProgressObject>
5249 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5250 {
5251 task_options _taskOptinos(_Cts.get_token());
5252 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5253 return task<void>(_Func(_Progress), _taskOptinos);
5254 }
5255
5256 template<typename _Function, typename _ProgressObject>
5257 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5258 {
5259 task_options _taskOptinos(_Cts.get_token());
5260 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5261 return task<void>(_Func(_Progress, _Cts.get_token()), _taskOptinos);
5262 }
5263 };
5264
5265 //
5266 // Functor returns a result - it needs to be wrapped in a task:
5267 //
5268 template<typename _ReturnType>
5269 struct _SelectorTaskGenerator<_TypeSelectorNoAsync, _ReturnType>
5270 {
5271
5272 #pragma warning(push)
5273 #pragma warning(disable: 4702)
5274 template<typename _Function>
5275 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5276 {
5277 task_options _taskOptinos(_Cts.get_token());
5278 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5279 return task<_ReturnType>( [=]() -> _ReturnType {
5280 _Task_generator_oversubscriber_t _Oversubscriber;
5281 (_Oversubscriber);
5282 return _Func();
5283 }, _taskOptinos);
5284 }
5285 #pragma warning(pop)
5286
5287 template<typename _Function>
5288 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5289 {
5290 task_options _taskOptinos(_Cts.get_token());
5291 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5292 return task<_ReturnType>( [=]() -> _ReturnType {
5293 _Task_generator_oversubscriber_t _Oversubscriber;
5294 (_Oversubscriber);
5295 return _Func(_Cts.get_token());
5296 }, _taskOptinos);
5297 }
5298
5299 template<typename _Function, typename _ProgressObject>
5300 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5301 {
5302 task_options _taskOptinos(_Cts.get_token());
5303 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5304 return task<_ReturnType>( [=]() -> _ReturnType {
5305 _Task_generator_oversubscriber_t _Oversubscriber;
5306 (_Oversubscriber);
5307 return _Func(_Progress);
5308 }, _taskOptinos);
5309 }
5310
5311 template<typename _Function, typename _ProgressObject>
5312 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5313 {
5314 task_options _taskOptinos(_Cts.get_token());
5315 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5316 return task<_ReturnType>( [=]() -> _ReturnType {
5317 _Task_generator_oversubscriber_t _Oversubscriber;
5318 (_Oversubscriber);
5319 return _Func(_Progress, _Cts.get_token());
5320 }, _taskOptinos);
5321 }
5322 };
5323
5324 template<>
5325 struct _SelectorTaskGenerator<_TypeSelectorNoAsync, void>
5326 {
5327 template<typename _Function>
5328 static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5329 {
5330 task_options _taskOptinos(_Cts.get_token());
5331 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5332 return task<void>( [=]() {
5333 _Task_generator_oversubscriber_t _Oversubscriber;
5334 (_Oversubscriber);
5335 _Func();
5336 }, _taskOptinos);
5337 }
5338
5339 template<typename _Function>
5340 static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5341 {
5342 task_options _taskOptinos(_Cts.get_token());
5343 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5344 return task<void>( [=]() {
5345 _Task_generator_oversubscriber_t _Oversubscriber;
5346 (_Oversubscriber);
5347 _Func(_Cts.get_token());
5348 }, _taskOptinos);
5349 }
5350
5351 template<typename _Function, typename _ProgressObject>
5352 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5353 {
5354 task_options _taskOptinos(_Cts.get_token());
5355 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5356 return task<void>( [=]() {
5357 _Task_generator_oversubscriber_t _Oversubscriber;
5358 (_Oversubscriber);
5359 _Func(_Progress);
5360 }, _taskOptinos);
5361 }
5362
5363 template<typename _Function, typename _ProgressObject>
5364 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5365 {
5366 task_options _taskOptinos(_Cts.get_token());
5367 details::_get_internal_task_options(_taskOptinos)._set_creation_callstack(_callstack);
5368 return task<void>( [=]() {
5369 _Task_generator_oversubscriber_t _Oversubscriber;
5370 (_Oversubscriber);
5371 _Func(_Progress, _Cts.get_token());
5372 }, _taskOptinos);
5373 }
5374 };
5375
5376 //
5377 // Functor returns a task - the task can directly be returned:
5378 //
5379 template<typename _ReturnType>
5380 struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, _ReturnType>
5381 {
5382 template<typename _Function>
5383 static task<_ReturnType> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5384 {
5385 return _Func();
5386 }
5387
5388 template<typename _Function>
5389 static task<_ReturnType> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5390 {
5391 return _Func(_Cts.get_token());
5392 }
5393
5394 template<typename _Function, typename _ProgressObject>
5395 static task<_ReturnType> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5396 {
5397 return _Func(_Progress);
5398 }
5399
5400 template<typename _Function, typename _ProgressObject>
5401 static task<_ReturnType> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5402 {
5403 return _Func(_Progress, _Cts.get_token());
5404 }
5405 };
5406
5407 template<>
5408 struct _SelectorTaskGenerator<_TypeSelectorAsyncTask, void>
5409 {
5410 template<typename _Function>
5411 static task<void> _GenerateTask_0(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5412 {
5413 return _Func();
5414 }
5415
5416 template<typename _Function>
5417 static task<void> _GenerateTask_1C(const _Function& _Func, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5418 {
5419 return _Func(_Cts.get_token());
5420 }
5421
5422 template<typename _Function, typename _ProgressObject>
5423 static task<void> _GenerateTask_1P(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5424 {
5425 return _Func(_Progress);
5426 }
5427
5428 template<typename _Function, typename _ProgressObject>
5429 static task<void> _GenerateTask_2PC(const _Function& _Func, const _ProgressObject& _Progress, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5430 {
5431 return _Func(_Progress, _Cts.get_token());
5432 }
5433 };
5434
5435 template<typename _Generator, bool _TakesToken, bool TakesProgress>
5436 struct _TaskGenerator
5437 {
5438 };
5439
5440 template<typename _Generator>
5441 struct _TaskGenerator<_Generator, false, false>
5442 {
5443 template<typename _Function, typename _ClassPtr, typename _ProgressType>
5444 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5445 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5446 {
5447 return _Generator::_GenerateTask_0(_Func, _Cts, _callstack);
5448 }
5449 };
5450
5451 template<typename _Generator>
5452 struct _TaskGenerator<_Generator, true, false>
5453 {
5454 template<typename _Function, typename _ClassPtr, typename _ProgressType>
5455 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5456 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5457 {
5458 return _Generator::_GenerateTask_1C(_Func, _Cts, _callstack);
5459 }
5460 };
5461
5462 template<typename _Generator>
5463 struct _TaskGenerator<_Generator, false, true>
5464 {
5465 template<typename _Function, typename _ClassPtr, typename _ProgressType>
5466 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5467 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5468 {
5469 return _Generator::_GenerateTask_1P(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
5470 }
5471 };
5472
5473 template<typename _Generator>
5474 struct _TaskGenerator<_Generator, true, true>
5475 {
5476 template<typename _Function, typename _ClassPtr, typename _ProgressType>
5477 static auto _GenerateTask(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5478 -> decltype(_Generator::_GenerateTask_0(_Func, _Cts, _callstack))
5479 {
5480 return _Generator::_GenerateTask_2PC(_Func, progress_reporter<_ProgressType>::_CreateReporter(_Ptr), _Cts, _callstack);
5481 }
5482 };
5483
5484 // ***************************************************************************
5485 // Async Operation Attributes Classes
5486 //
5487 // These classes are passed through the hierarchy of async base classes in order to hold multiple attributes of a given async construct in
5488 // a single container. An attribute class must define:
5489 //
5490 // Mandatory:
5491 // -------------------------
5492 //
5493 // _AsyncBaseType : The Windows Runtime interface which is being implemented.
5494 // _CompletionDelegateType : The Windows Runtime completion delegate type for the interface.
5495 // _ProgressDelegateType : If _TakesProgress is true, the Windows Runtime progress delegate type for the interface. If it is false, an empty Windows Runtime type.
5496 // _ReturnType : The return type of the async construct (void for actions / non-void for operations)
5497 //
5498 // _TakesProgress : An indication as to whether or not
5499 //
5500 // _Generate_Task : A function adapting the user's function into what's necessary to produce the appropriate task
5501 //
5502 // Optional:
5503 // -------------------------
5504 //
5505
5506 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken, bool _TakesProgress>
5507 struct _AsyncAttributes
5508 {
5509 };
5510
5511 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
5512 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, true>
5513 {
5514 typedef typename Windows::Foundation::IAsyncOperationWithProgress<_ReturnType, _ProgressType> _AsyncBaseType;
5515 typedef typename Windows::Foundation::AsyncOperationProgressHandler<_ReturnType, _ProgressType> _ProgressDelegateType;
5516 typedef typename Windows::Foundation::AsyncOperationWithProgressCompletedHandler<_ReturnType, _ProgressType> _CompletionDelegateType;
5517 typedef typename _ReturnType _ReturnType;
5518 typedef typename _ProgressType _ProgressType;
5519 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5520 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5521 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
5522
5523 static const bool _TakesProgress = true;
5524 static const bool _TakesToken = _TakesToken;
5525
5526 template<typename _Function, typename _ClassPtr>
5527 static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5528 {
5529 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5530 }
5531 };
5532
5533 template<typename _Function, typename _ProgressType, typename _ReturnType, typename _TaskTraits, bool _TakesToken>
5534 struct _AsyncAttributes<_Function, _ProgressType, _ReturnType, _TaskTraits, _TakesToken, false>
5535 {
5536 typedef typename Windows::Foundation::IAsyncOperation<_ReturnType> _AsyncBaseType;
5537 typedef _Zip _ProgressDelegateType;
5538 typedef typename Windows::Foundation::AsyncOperationCompletedHandler<_ReturnType> _CompletionDelegateType;
5539 typedef typename _ReturnType _ReturnType;
5540 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5541 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5542 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
5543
5544 static const bool _TakesProgress = false;
5545 static const bool _TakesToken = _TakesToken;
5546
5547 template<typename _Function, typename _ClassPtr>
5548 static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5549 {
5550 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5551 }
5552 };
5553
5554 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
5555 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, true>
5556 {
5557 typedef typename Windows::Foundation::IAsyncActionWithProgress<_ProgressType> _AsyncBaseType;
5558 typedef typename Windows::Foundation::AsyncActionProgressHandler<_ProgressType> _ProgressDelegateType;
5559 typedef typename Windows::Foundation::AsyncActionWithProgressCompletedHandler<_ProgressType> _CompletionDelegateType;
5560 typedef void _ReturnType;
5561 typedef typename _ProgressType _ProgressType;
5562 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5563 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5564 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, true> _TaskGenerator;
5565
5566 static const bool _TakesProgress = true;
5567 static const bool _TakesToken = _TakesToken;
5568
5569 template<typename _Function, typename _ClassPtr>
5570 static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5571 {
5572 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5573 }
5574 };
5575
5576 template<typename _Function, typename _ProgressType, typename _TaskTraits, bool _TakesToken>
5577 struct _AsyncAttributes<_Function, _ProgressType, void, _TaskTraits, _TakesToken, false>
5578 {
5579 typedef typename Windows::Foundation::IAsyncAction _AsyncBaseType;
5580 typedef _Zip _ProgressDelegateType;
5581 typedef typename Windows::Foundation::AsyncActionCompletedHandler _CompletionDelegateType;
5582 typedef void _ReturnType;
5583 typedef typename _TaskTraits::_AsyncKind _AsyncKind;
5584 typedef typename _SelectorTaskGenerator<_AsyncKind, _ReturnType> _SelectorTaskGenerator;
5585 typedef typename _TaskGenerator<_SelectorTaskGenerator, _TakesToken, false> _TaskGenerator;
5586
5587 static const bool _TakesProgress = false;
5588 static const bool _TakesToken = _TakesToken;
5589
5590 template<typename _Function, typename _ClassPtr>
5591 static task<_ReturnType> _Generate_Task(const _Function& _Func, _ClassPtr _Ptr, cancellation_token_source _Cts, const _TaskCreationCallstack & _callstack)
5592 {
5593 return _TaskGenerator::_GenerateTask<_Function, _ClassPtr, _ProgressType>(_Func, _Ptr, _Cts, _callstack);
5594 }
5595 };
5596
5597 template<typename _Function>
5598 struct _AsyncLambdaTypeTraits
5599 {
5600 typedef typename _FunctorTypeTraits<_Function>::_ReturnType _ReturnType;
5601 typedef typename _FunctorTypeTraits<_Function>::_Argument1Type _Argument1Type;
5602 typedef typename _CAFunctorOptions<_Function>::_ProgressType _ProgressType;
5603
5604 static const bool _TakesProgress = _CAFunctorOptions<_Function>::_TakesProgress;
5605 static const bool _TakesToken = _CAFunctorOptions<_Function>::_TakesToken;
5606
5607 typedef typename _TaskTypeTraits<_ReturnType> _TaskTraits;
5608 typedef typename _AsyncAttributes<_Function, _ProgressType, typename _TaskTraits::_TaskRetType, _TaskTraits, _TakesToken, _TakesProgress> _AsyncAttributes;
5609 };
5610
5611 // ***************************************************************************
5612 // AsyncInfo (and completion) Layer:
5613 //
5614
5615 //
5616 // Internal base class implementation for async operations (based on internal Windows representation for ABI level async operations)
5617 //
5618 template < typename _Attributes, _AsyncResultType resultType = SingleResult >
5619 ref class _AsyncInfoBase abstract : _Attributes::_AsyncBaseType
5620 {
5621 internal:
5622
5623 _AsyncInfoBase() :
5624 _M_currentStatus(_AsyncStatusInternal::_AsyncCreated),
5625 _M_errorCode(S_OK),
5626 _M_completeDelegate(nullptr),
5627 _M_CompleteDelegateAssigned(0),
5628 _M_CallbackMade(0)
5629 {
5630 _M_id = ::pplx::details::platform::GetNextAsyncId();
5631 }
5632
5633 public:
5634 virtual typename _Attributes::_ReturnType GetResults()
5635 {
5636 throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5637 }
5638
5639 virtual property unsigned int Id
5640 {
5641 unsigned int get()
5642 {
5643 _CheckValidStateForAsyncInfoCall();
5644
5645 return _M_id;
5646 }
5647
5648 void set(unsigned int id)
5649 {
5650 _CheckValidStateForAsyncInfoCall();
5651
5652 if (id == 0)
5653 {
5654 throw ::Platform::Exception::CreateException(E_INVALIDARG);
5655 }
5656 else if (_M_currentStatus != _AsyncStatusInternal::_AsyncCreated)
5657 {
5658 throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5659 }
5660
5661 _M_id = id;
5662 }
5663 }
5664
5665 virtual property Windows::Foundation::AsyncStatus Status
5666 {
5667 Windows::Foundation::AsyncStatus get()
5668 {
5669 _CheckValidStateForAsyncInfoCall();
5670
5671 _AsyncStatusInternal _Current = _M_currentStatus;
5672
5673 //
5674 // Map our internal cancel pending to cancelled. This way "pending cancelled" looks to the outside as "cancelled" but
5675 // can still transition to "completed" if the operation completes without acknowledging the cancellation request
5676 //
5677 switch(_Current)
5678 {
5679 case _AsyncCancelPending:
5680 _Current = _AsyncCanceled;
5681 break;
5682 case _AsyncCreated:
5683 _Current = _AsyncStarted;
5684 break;
5685 default:
5686 break;
5687 }
5688
5689 return static_cast<Windows::Foundation::AsyncStatus>(_Current);
5690 }
5691 }
5692
5693 virtual property Windows::Foundation::HResult ErrorCode
5694 {
5695 Windows::Foundation::HResult get()
5696 {
5697 _CheckValidStateForAsyncInfoCall();
5698
5699 Windows::Foundation::HResult _Hr;
5700 _Hr.Value = _M_errorCode;
5701 return _Hr;
5702 }
5703 }
5704
5705 virtual property typename _Attributes::_ProgressDelegateType^ Progress
5706 {
5707 typename typename _Attributes::_ProgressDelegateType^ get()
5708 {
5709 return _GetOnProgress();
5710 }
5711
5712 void set(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)
5713 {
5714 _PutOnProgress(_ProgressHandler);
5715 }
5716 }
5717
5718 virtual void Cancel()
5719 {
5720 if (_TransitionToState(_AsyncCancelPending))
5721 {
5722 _OnCancel();
5723 }
5724 }
5725
5726 virtual void Close()
5727 {
5728 if (_TransitionToState(_AsyncClosed))
5729 {
5730 _OnClose();
5731 }
5732 else
5733 {
5734 if (_M_currentStatus != _AsyncClosed) // Closed => Closed transition is just ignored
5735 {
5736 throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);
5737 }
5738 }
5739 }
5740
5741 virtual property typename _Attributes::_CompletionDelegateType^ Completed
5742 {
5743 typename _Attributes::_CompletionDelegateType^ get()
5744 {
5745 _CheckValidStateForDelegateCall();
5746 return _M_completeDelegate;
5747 }
5748
5749 void set(typename _Attributes::_CompletionDelegateType^ _CompleteHandler)
5750 {
5751 _CheckValidStateForDelegateCall();
5752 // this delegate property is "write once"
5753 if (InterlockedIncrement(&_M_CompleteDelegateAssigned) == 1)
5754 {
5755 _M_completeDelegateContext = _ContextCallback::_CaptureCurrent();
5756 _M_completeDelegate = _CompleteHandler;
5757 // Guarantee that the write of _M_completeDelegate is ordered with respect to the read of state below
5758 // as perceived from _FireCompletion on another thread.
5759 MemoryBarrier();
5760 if (_IsTerminalState())
5761 {
5762 _FireCompletion();
5763 }
5764 }
5765 else
5766 {
5767 throw ::Platform::Exception::CreateException(E_ILLEGAL_DELEGATE_ASSIGNMENT);
5768 }
5769 }
5770 }
5771
5772
5773 protected private:
5774
5775 // _Start - this is not externally visible since async operations "hot start" before returning to the caller
5776 void _Start()
5777 {
5778 if (_TransitionToState(_AsyncStarted))
5779 {
5780 _OnStart();
5781 }
5782 else
5783 {
5784 throw ::Platform::Exception::CreateException(E_ILLEGAL_STATE_CHANGE);
5785 }
5786 }
5787
5788
5789 void _FireCompletion()
5790 {
5791 _TryTransitionToCompleted();
5792
5793 // we guarantee that completion can only ever be fired once
5794 if (_M_completeDelegate != nullptr && InterlockedIncrement(&_M_CallbackMade) == 1)
5795 {
5796 _M_completeDelegateContext._CallInContext([=] {
5797 _M_completeDelegate((_Attributes::_AsyncBaseType^)this, this->Status);
5798 _M_completeDelegate = nullptr;
5799 });
5800 }
5801 }
5802
5803 virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress()
5804 {
5805 throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5806 }
5807
5808 virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler)
5809 {
5810 throw ::Platform::Exception::CreateException(E_UNEXPECTED);
5811 }
5812
5813 bool _TryTransitionToCompleted()
5814 {
5815 return _TransitionToState(_AsyncStatusInternal::_AsyncCompleted);
5816 }
5817
5818 bool _TryTransitionToCancelled()
5819 {
5820 return _TransitionToState(_AsyncStatusInternal::_AsyncCanceled);
5821 }
5822
5823 bool _TryTransitionToError(const HRESULT error)
5824 {
5825 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_errorCode), error, S_OK);
5826 return _TransitionToState(_AsyncStatusInternal::_AsyncError);
5827 }
5828
5829 // This method checks to see if the delegate properties can be
5830 // modified in the current state and generates the appropriate
5831 // error hr in the case of violation.
5832 inline void _CheckValidStateForDelegateCall()
5833 {
5834 if (_M_currentStatus == _AsyncClosed)
5835 {
5836 throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5837 }
5838 }
5839
5840 // This method checks to see if results can be collected in the
5841 // current state and generates the appropriate error hr in
5842 // the case of a violation.
5843 inline void _CheckValidStateForResultsCall()
5844 {
5845 _AsyncStatusInternal _Current = _M_currentStatus;
5846
5847 if (_Current == _AsyncError)
5848 {
5849 throw ::Platform::Exception::CreateException(_M_errorCode);
5850 }
5851 #pragma warning(push)
5852 #pragma warning(disable: 4127) // Conditional expression is constant
5853 // single result illegal before transition to Completed or Cancelled state
5854 if (resultType == SingleResult)
5855 #pragma warning(pop)
5856 {
5857 if (_Current != _AsyncCompleted)
5858 {
5859 throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5860 }
5861 }
5862 // multiple results can be called after Start has been called and before/after Completed
5863 else if (_Current != _AsyncStarted &&
5864 _Current != _AsyncCancelPending &&
5865 _Current != _AsyncCanceled &&
5866 _Current != _AsyncCompleted)
5867 {
5868 throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5869 }
5870 }
5871
5872 // This method can be called by derived classes periodically to determine
5873 // whether the asynchronous operation should continue processing or should
5874 // be halted.
5875 inline bool _ContinueAsyncOperation()
5876 {
5877 return (_M_currentStatus == _AsyncStarted);
5878 }
5879
5880 // These two methods are used to allow the async worker implementation do work on
5881 // state transitions. No real "work" should be done in these methods. In other words
5882 // they should not block for a long time on UI timescales.
5883 virtual void _OnStart() = 0;
5884 virtual void _OnClose() = 0;
5885 virtual void _OnCancel() = 0;
5886
5887 private:
5888
5889 // This method is used to check if calls to the AsyncInfo properties
5890 // (id, status, errorcode) are legal in the current state. It also
5891 // generates the appropriate error hr to return in the case of an
5892 // illegal call.
5893 inline void _CheckValidStateForAsyncInfoCall()
5894 {
5895 _AsyncStatusInternal _Current = _M_currentStatus;
5896 if (_Current == _AsyncClosed)
5897 {
5898 throw ::Platform::Exception::CreateException(E_ILLEGAL_METHOD_CALL);
5899 }
5900 else if (_Current == _AsyncCreated)
5901 {
5902 throw ::Platform::Exception::CreateException(E_ASYNC_OPERATION_NOT_STARTED);
5903 }
5904
5905 }
5906
5907 inline bool _TransitionToState(const _AsyncStatusInternal _NewState)
5908 {
5909 _AsyncStatusInternal _Current = _M_currentStatus;
5910
5911 // This enforces the valid state transitions of the asynchronous worker object
5912 // state machine.
5913 switch(_NewState)
5914 {
5915 case _AsyncStatusInternal::_AsyncStarted:
5916 if (_Current != _AsyncCreated)
5917 {
5918 return false;
5919 }
5920 break;
5921 case _AsyncStatusInternal::_AsyncCompleted:
5922 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5923 {
5924 return false;
5925 }
5926 break;
5927 case _AsyncStatusInternal::_AsyncCancelPending:
5928 if (_Current != _AsyncStarted)
5929 {
5930 return false;
5931 }
5932 break;
5933 case _AsyncStatusInternal::_AsyncCanceled:
5934 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5935 {
5936 return false;
5937 }
5938 break;
5939 case _AsyncStatusInternal::_AsyncError:
5940 if (_Current != _AsyncStarted && _Current != _AsyncCancelPending)
5941 {
5942 return false;
5943 }
5944 break;
5945 case _AsyncStatusInternal::_AsyncClosed:
5946 if (!_IsTerminalState(_Current))
5947 {
5948 return false;
5949 }
5950 break;
5951 default:
5952 return false;
5953 break;
5954 }
5955
5956 // attempt the transition to the new state
5957 // Note: if currentStatus_ == _Current, then there was no intervening write
5958 // by the async work object and the swap succeeded.
5959 _AsyncStatusInternal _RetState = static_cast<_AsyncStatusInternal>(
5960 _InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(&_M_currentStatus),
5961 _NewState,
5962 static_cast<LONG>(_Current)));
5963
5964 // ICE returns the former state, if the returned state and the
5965 // state we captured at the beginning of this method are the same,
5966 // the swap succeeded.
5967 return (_RetState == _Current);
5968 }
5969
5970 inline bool _IsTerminalState()
5971 {
5972 return _IsTerminalState(_M_currentStatus);
5973 }
5974
5975 inline bool _IsTerminalState(_AsyncStatusInternal status)
5976 {
5977 return (status == _AsyncError ||
5978 status == _AsyncCanceled ||
5979 status == _AsyncCompleted ||
5980 status == _AsyncClosed);
5981 }
5982
5983 private:
5984
5985 _ContextCallback _M_completeDelegateContext;
5986 typename _Attributes::_CompletionDelegateType^ volatile _M_completeDelegate;
5987 _AsyncStatusInternal volatile _M_currentStatus;
5988 HRESULT volatile _M_errorCode;
5989 unsigned int _M_id;
5990 long volatile _M_CompleteDelegateAssigned;
5991 long volatile _M_CallbackMade;
5992 };
5993
5994 // ***************************************************************************
5995 // Progress Layer (optional):
5996 //
5997
5998 template< typename _Attributes, bool _HasProgress, _AsyncResultType _ResultType = SingleResult >
5999 ref class _AsyncProgressBase abstract : _AsyncInfoBase<_Attributes, _ResultType>
6000 {
6001 };
6002
6003 template< typename _Attributes, _AsyncResultType _ResultType>
6004 ref class _AsyncProgressBase<_Attributes, true, _ResultType> abstract : _AsyncInfoBase<_Attributes, _ResultType>
6005 {
6006 internal:
6007
6008 _AsyncProgressBase() : _AsyncInfoBase<_Attributes, _ResultType>(),
6009 _M_progressDelegate(nullptr)
6010 {
6011 }
6012
6013 virtual typename _Attributes::_ProgressDelegateType^ _GetOnProgress() override
6014 {
6015 _CheckValidStateForDelegateCall();
6016 return _M_progressDelegate;
6017 }
6018
6019 virtual void _PutOnProgress(typename _Attributes::_ProgressDelegateType^ _ProgressHandler) override
6020 {
6021 _CheckValidStateForDelegateCall();
6022 _M_progressDelegate = _ProgressHandler;
6023 _M_progressDelegateContext = _ContextCallback::_CaptureCurrent();
6024 }
6025
6026 void _FireProgress(const typename _Attributes::_ProgressType& _ProgressValue)
6027 {
6028 if (_M_progressDelegate != nullptr)
6029 {
6030 _M_progressDelegateContext._CallInContext([=] {
6031 _M_progressDelegate((_Attributes::_AsyncBaseType^)this, _ProgressValue);
6032 });
6033 }
6034 }
6035
6036 private:
6037
6038 _ContextCallback _M_progressDelegateContext;
6039 typename _Attributes::_ProgressDelegateType^ _M_progressDelegate;
6040 };
6041
6042 template<typename _Attributes, _AsyncResultType _ResultType = SingleResult>
6043 ref class _AsyncBaseProgressLayer abstract : _AsyncProgressBase<_Attributes, _Attributes::_TakesProgress, _ResultType>
6044 {
6045 };
6046
6047 // ***************************************************************************
6048 // Task Adaptation Layer:
6049 //
6050
6051 //
6052 // _AsyncTaskThunkBase provides a bridge between IAsync<Action/Operation> and task.
6053 //
6054 template<typename _Attributes, typename _ReturnType>
6055 ref class _AsyncTaskThunkBase abstract : _AsyncBaseProgressLayer<_Attributes>
6056 {
6057 public:
6058
6059 virtual _ReturnType GetResults() override
6060 {
6061 _CheckValidStateForResultsCall();
6062 return _M_task.get();
6063 }
6064
6065 internal:
6066
6067 typedef task<_ReturnType> _TaskType;
6068
6069 _AsyncTaskThunkBase(const _TaskType& _Task)
6070 : _M_task(_Task)
6071 {
6072 }
6073
6074 _AsyncTaskThunkBase()
6075 {
6076 }
6077
6078 protected:
6079
6080 virtual void _OnStart() override
6081 {
6082 _M_task.then( [=](_TaskType _Antecedent) {
6083 try
6084 {
6085 _Antecedent.get();
6086 }
6087 catch(task_canceled&)
6088 {
6089 _TryTransitionToCancelled();
6090 }
6091 catch(::Platform::Exception^ _Ex)
6092 {
6093 _TryTransitionToError(_Ex->HResult);
6094 }
6095 catch(...)
6096 {
6097 _TryTransitionToError(E_FAIL);
6098 }
6099 _FireCompletion();
6100 });
6101 }
6102
6103 internal:
6104
6105 _TaskType _M_task;
6106 cancellation_token_source _M_cts;
6107 };
6108
6109 template<typename _Attributes>
6110 ref class _AsyncTaskThunk : _AsyncTaskThunkBase<_Attributes, typename _Attributes::_ReturnType>
6111 {
6112 internal:
6113
6114 _AsyncTaskThunk(const _TaskType& _Task) :
6115 _AsyncTaskThunkBase(_Task)
6116 {
6117 }
6118
6119 _AsyncTaskThunk()
6120 {
6121 }
6122
6123 protected:
6124
6125 virtual void _OnClose() override
6126 {
6127 }
6128
6129 virtual void _OnCancel() override
6130 {
6131 _M_cts.cancel();
6132 }
6133 };
6134
6135 // ***************************************************************************
6136 // Async Creation Layer:
6137 //
6138 template<typename _Function>
6139 ref class _AsyncTaskGeneratorThunk sealed : _AsyncTaskThunk<typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes>
6140 {
6141 internal:
6142
6143 typedef typename _AsyncLambdaTypeTraits<_Function>::_AsyncAttributes _Attributes;
6144 typedef typename _AsyncTaskThunk<_Attributes> _Base;
6145 typedef typename _Attributes::_AsyncBaseType _AsyncBaseType;
6146
6147 _AsyncTaskGeneratorThunk(const _Function& _Func, const _TaskCreationCallstack &_callstack) : _M_func(_Func), _M_creationCallstack(_callstack)
6148 {
6149 // Virtual call here is safe as the class is declared 'sealed'
6150 _Start();
6151 }
6152
6153 protected:
6154
6155 //
6156 // The only thing we must do different from the base class is we must spin the hot task on transition from Created->Started. Otherwise,
6157 // let the base thunk handle everything.
6158 //
6159
6160 virtual void _OnStart() override
6161 {
6162 //
6163 // Call the appropriate task generator to actually produce a task of the expected type. This might adapt the user lambda for progress reports,
6164 // wrap the return result in a task, or allow for direct return of a task depending on the form of the lambda.
6165 //
6166 _M_task = _Attributes::_Generate_Task(_M_func, this, _M_cts, _M_creationCallstack);
6167 _Base::_OnStart();
6168 }
6169
6170 virtual void _OnCancel() override
6171 {
6172 _Base::_OnCancel();
6173 }
6174
6175 private:
6176 _TaskCreationCallstack _M_creationCallstack;
6177 _Function _M_func;
6178 };
6179 } // namespace details
6180
6220
6221 template<typename _Function>
6223 details::_AsyncTaskGeneratorThunk<_Function> ^create_async(const _Function& _Func)
6224 {
6225 static_assert(std::is_same<decltype(details::_IsValidCreateAsync(_Func,0,0,0,0)),std::true_type>::value,
6226 "argument to create_async must be a callable object taking zero, one or two arguments");
6227 return ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func, _CAPTURE_CALLSTACK());
6228 }
6229
6230 #endif /* defined (__cplusplus_winrt) */
6231
6232 namespace details
6233 {
6234 // Helper struct for when_all operators to know when tasks have completed
6235 template<typename _Type>
6236 struct _RunAllParam
6237 {
6238 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6239 {
6240 }
6241
6242 void _Resize(size_t _Len, bool _SkipVector = false)
6243 {
6244 _M_numTasks = _Len;
6245 if (!_SkipVector)
6246 {
6247 _M_vector._Result.resize(_Len);
6248 }
6249 }
6250
6251 task_completion_event<_Unit_type> _M_completed;
6252 _ResultHolder<std::vector<_Type> > _M_vector;
6253 _ResultHolder<_Type> _M_mergeVal;
6254 atomic_size_t _M_completeCount;
6255 size_t _M_numTasks;
6256 };
6257
6258 template<typename _Type>
6259 struct _RunAllParam<std::vector<_Type> >
6260 {
6261 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6262 {
6263 }
6264
6265 void _Resize(size_t _Len, bool _SkipVector = false)
6266 {
6267 _M_numTasks = _Len;
6268
6269 if (!_SkipVector)
6270 {
6271 _M_vector.resize(_Len);
6272 }
6273 }
6274
6275 task_completion_event<_Unit_type> _M_completed;
6276 std::vector<_ResultHolder<std::vector<_Type> > > _M_vector;
6277 atomic_size_t _M_completeCount;
6278 size_t _M_numTasks;
6279 };
6280
6281 // Helper struct specialization for void
6282 template<>
6283 struct _RunAllParam<_Unit_type>
6284 {
6285 _RunAllParam() : _M_completeCount(0), _M_numTasks(0)
6286 {
6287 }
6288
6289 void _Resize(size_t _Len)
6290 {
6291 _M_numTasks = _Len;
6292 }
6293
6294 task_completion_event<_Unit_type> _M_completed;
6295 atomic_size_t _M_completeCount;
6296 size_t _M_numTasks;
6297 };
6298
6299 inline void _JoinAllTokens_Add(const cancellation_token_source& _MergedSrc, _CancellationTokenState *_PJoinedTokenState)
6300 {
6301 if (_PJoinedTokenState != nullptr && _PJoinedTokenState != _CancellationTokenState::_None())
6302 {
6303 cancellation_token _T = cancellation_token::_FromImpl(_PJoinedTokenState);
6304 _T.register_callback( [=](){
6305 _MergedSrc.cancel();
6306 });
6307 }
6308 }
6309
6310 template<typename _ElementType, typename _Function, typename _TaskType>
6311 void _WhenAllContinuationWrapper(_RunAllParam<_ElementType>* _PParam, _Function _Func, task<_TaskType>& _Task)
6312 {
6313 if (_Task._GetImpl()->_IsCompleted())
6314 {
6315 _Func();
6316 if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6317 {
6318 // Inline execute its direct continuation, the _ReturnTask
6319 _PParam->_M_completed.set(_Unit_type());
6320 // It's safe to delete it since all usage of _PParam in _ReturnTask has been finished.
6321 delete _PParam;
6322 }
6323 }
6324 else
6325 {
6326 _ASSERTE(_Task._GetImpl()->_IsCanceled());
6327 if (_Task._GetImpl()->_HasUserException())
6328 {
6329 // _Cancel will return false if the TCE is already canceled with or without exception
6330 _PParam->_M_completed._Cancel(_Task._GetImpl()->_GetExceptionHolder());
6331 }
6332 else
6333 {
6334 _PParam->_M_completed._Cancel();
6335 }
6336
6337 if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6338 {
6339 delete _PParam;
6340 }
6341 }
6342 }
6343
6344 template<typename _ElementType, typename _Iterator>
6345 struct _WhenAllImpl
6346 {
6347 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6348 {
6349 _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6350
6351 auto _PParam = new _RunAllParam<_ElementType>();
6352 cancellation_token_source _MergedSource;
6353
6354 // Step1: Create task completion event.
6355 task_options _Options(_TaskOptions);
6356 _Options.set_cancellation_token(_MergedSource.get_token());
6357 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6358 // The return task must be created before step 3 to enforce inline execution.
6359 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {
6360 return _PParam->_M_vector.Get();
6361 }, nullptr);
6362
6363 // Step2: Combine and check tokens, and count elements in range.
6364 if (_PTokenState)
6365 {
6366 _JoinAllTokens_Add(_MergedSource, _PTokenState);
6367 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6368 }
6369 else
6370 {
6371 size_t _TaskNum = 0;
6372 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6373 {
6374 _TaskNum++;
6375 _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6376 }
6377 _PParam->_Resize(_TaskNum);
6378 }
6379
6380 // Step3: Check states of previous tasks.
6381 if( _Begin == _End )
6382 {
6383 _PParam->_M_completed.set(_Unit_type());
6384 delete _PParam;
6385 }
6386 else
6387 {
6388 size_t _Index = 0;
6389 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6390 {
6391 if (_PTask->is_apartment_aware())
6392 {
6393 _ReturnTask._SetAsync();
6394 }
6395
6396 _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {
6397
6398 auto _PParamCopy = _PParam;
6399 auto _IndexCopy = _Index;
6400 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask](){
6401 _PParamCopy->_M_vector._Result[_IndexCopy] = _ResultTask._GetImpl()->_GetResult();
6402 };
6403
6404 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6405 }, _CancellationTokenState::_None());
6406
6407 _Index++;
6408 }
6409 }
6410
6411 return _ReturnTask;
6412 }
6413 };
6414
6415 template<typename _ElementType, typename _Iterator>
6416 struct _WhenAllImpl<std::vector<_ElementType>, _Iterator>
6417 {
6418 static task<std::vector<_ElementType>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6419 {
6420 _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6421
6422 auto _PParam = new _RunAllParam<std::vector<_ElementType>>();
6423 cancellation_token_source _MergedSource;
6424
6425 // Step1: Create task completion event.
6426 task_options _Options(_TaskOptions);
6427 _Options.set_cancellation_token(_MergedSource.get_token());
6428 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6429 // The return task must be created before step 3 to enforce inline execution.
6430 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ElementType> {
6431 _ASSERTE(_PParam->_M_completeCount == _PParam->_M_numTasks);
6432 std::vector<_ElementType> _Result;
6433 for(size_t _I = 0; _I < _PParam->_M_numTasks; _I++)
6434 {
6435 const std::vector<_ElementType>& _Vec = _PParam->_M_vector[_I].Get();
6436 _Result.insert(_Result.end(), _Vec.begin(), _Vec.end());
6437 }
6438 return _Result;
6439 }, nullptr);
6440
6441 // Step2: Combine and check tokens, and count elements in range.
6442 if (_PTokenState)
6443 {
6444 _JoinAllTokens_Add(_MergedSource, _PTokenState);
6445 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6446 }
6447 else
6448 {
6449 size_t _TaskNum = 0;
6450 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6451 {
6452 _TaskNum++;
6453 _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6454 }
6455 _PParam->_Resize(_TaskNum);
6456 }
6457
6458 // Step3: Check states of previous tasks.
6459 if( _Begin == _End )
6460 {
6461 _PParam->_M_completed.set(_Unit_type());
6462 delete _PParam;
6463 }
6464 else
6465 {
6466 size_t _Index = 0;
6467 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6468 {
6469 if (_PTask->is_apartment_aware())
6470 {
6471 _ReturnTask._SetAsync();
6472 }
6473
6474 _PTask->_Then([_PParam, _Index](task<std::vector<_ElementType>> _ResultTask) {
6475
6476 auto _PParamCopy = _PParam;
6477 auto _IndexCopy = _Index;
6478 auto _Func = [_PParamCopy, _IndexCopy, &_ResultTask]() {
6479 _PParamCopy->_M_vector[_IndexCopy].Set(_ResultTask._GetImpl()->_GetResult());
6480 };
6481
6482 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6483 }, _CancellationTokenState::_None());
6484
6485 _Index++;
6486 }
6487 }
6488
6489 return _ReturnTask;
6490 }
6491 };
6492
6493 template<typename _Iterator>
6494 struct _WhenAllImpl<void, _Iterator>
6495 {
6496 static task<void> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6497 {
6498 _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6499
6500 auto _PParam = new _RunAllParam<_Unit_type>();
6501 cancellation_token_source _MergedSource;
6502
6503 // Step1: Create task completion event.
6504 task_options _Options(_TaskOptions);
6505 _Options.set_cancellation_token(_MergedSource.get_token());
6506 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _Options);
6507 // The return task must be created before step 3 to enforce inline execution.
6508 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) {
6509 }, nullptr);
6510
6511 // Step2: Combine and check tokens, and count elements in range.
6512 if (_PTokenState)
6513 {
6514 _JoinAllTokens_Add(_MergedSource, _PTokenState);
6515 _PParam->_Resize(static_cast<size_t>(std::distance(_Begin, _End)));
6516 }
6517 else
6518 {
6519 size_t _TaskNum = 0;
6520 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6521 {
6522 _TaskNum++;
6523 _JoinAllTokens_Add(_MergedSource, _PTask->_GetImpl()->_M_pTokenState);
6524 }
6525 _PParam->_Resize(_TaskNum);
6526 }
6527
6528 // Step3: Check states of previous tasks.
6529 if( _Begin == _End )
6530 {
6531 _PParam->_M_completed.set(_Unit_type());
6532 delete _PParam;
6533 }
6534 else
6535 {
6536 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6537 {
6538 if (_PTask->is_apartment_aware())
6539 {
6540 _ReturnTask._SetAsync();
6541 }
6542
6543 _PTask->_Then([_PParam](task<void> _ResultTask) {
6544 auto _Func = [](){};
6545 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6546 }, _CancellationTokenState::_None());
6547 }
6548 }
6549
6550 return _ReturnTask;
6551 }
6552 };
6553
6554 template<typename _ReturnType>
6555 task<std::vector<_ReturnType>> _WhenAllVectorAndValue(const task<std::vector<_ReturnType>>& _VectorTask, const task<_ReturnType>& _ValueTask,
6556 bool _OutputVectorFirst)
6557 {
6558 auto _PParam = new _RunAllParam<_ReturnType>();
6559 cancellation_token_source _MergedSource;
6560
6561 // Step1: Create task completion event.
6562 task<_Unit_type> _All_tasks_completed(_PParam->_M_completed, _MergedSource.get_token());
6563 // The return task must be created before step 3 to enforce inline execution.
6564 auto _ReturnTask = _All_tasks_completed._Then([=](_Unit_type) -> std::vector<_ReturnType> {
6565 _ASSERTE(_PParam->_M_completeCount == 2);
6566 auto _Result = _PParam->_M_vector.Get(); // copy by value
6567 auto _mergeVal = _PParam->_M_mergeVal.Get();
6568
6569 if (_OutputVectorFirst == true)
6570 {
6571 _Result.push_back(_mergeVal);
6572 }
6573 else
6574 {
6575 _Result.insert(_Result.begin(), _mergeVal);
6576 }
6577 return _Result;
6578 }, nullptr);
6579
6580 // Step2: Combine and check tokens.
6581 _JoinAllTokens_Add(_MergedSource, _VectorTask._GetImpl()->_M_pTokenState);
6582 _JoinAllTokens_Add(_MergedSource, _ValueTask._GetImpl()->_M_pTokenState);
6583
6584 // Step3: Check states of previous tasks.
6585 _PParam->_Resize(2, true);
6586
6587 if (_VectorTask.is_apartment_aware() || _ValueTask.is_apartment_aware())
6588 {
6589 _ReturnTask._SetAsync();
6590 }
6591 _VectorTask._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {
6592 auto _PParamCopy = _PParam;
6593 auto _Func = [_PParamCopy, &_ResultTask]() {
6594 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
6595 _PParamCopy->_M_vector.Set(_ResultLocal);
6596 };
6597
6598 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6599 }, _CancellationTokenState::_None());
6600 _ValueTask._Then([_PParam](task<_ReturnType> _ResultTask) {
6601 auto _PParamCopy = _PParam;
6602 auto _Func = [_PParamCopy, &_ResultTask]() {
6603 auto _ResultLocal = _ResultTask._GetImpl()->_GetResult();
6604 _PParamCopy->_M_mergeVal.Set(_ResultLocal);
6605 };
6606
6607 _WhenAllContinuationWrapper(_PParam, _Func, _ResultTask);
6608 }, _CancellationTokenState::_None());
6609
6610 return _ReturnTask;
6611 }
6612 } // namespace details
6613
6636
6637 template <typename _Iterator>
6638 auto when_all(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
6639 -> decltype (details::_WhenAllImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
6640 {
6641 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
6642 return details::_WhenAllImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
6643 }
6644
6669
6670 template<typename _ReturnType>
6671 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
6672 {
6673 task<_ReturnType> _PTasks[2] = {_Lhs, _Rhs};
6674 return when_all(_PTasks, _PTasks+2);
6675 }
6676
6701
6702 template<typename _ReturnType>
6703 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
6704 {
6705 return details::_WhenAllVectorAndValue(_Lhs, _Rhs, true);
6706 }
6707
6732
6733 template<typename _ReturnType>
6734 task<std::vector<_ReturnType>> operator&&(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
6735 {
6736 return details::_WhenAllVectorAndValue(_Rhs, _Lhs, false);
6737 }
6738
6763
6764 template<typename _ReturnType>
6765 task<std::vector<_ReturnType>> operator&&(const task<std::vector<_ReturnType>> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
6766 {
6767 task<std::vector<_ReturnType>> _PTasks[2] = {_Lhs, _Rhs};
6768 return when_all(_PTasks, _PTasks+2);
6769 }
6770
6795
6796 inline task<void> operator&&(const task<void> & _Lhs, const task<void> & _Rhs)
6797 {
6798 task<void> _PTasks[2] = {_Lhs, _Rhs};
6799 return when_all(_PTasks, _PTasks+2);
6800 }
6801
6802 namespace details
6803 {
6804 // Helper struct for when_any operators to know when tasks have completed
6805 template <typename _CompletionType>
6806 struct _RunAnyParam
6807 {
6808 _RunAnyParam() : _M_exceptionRelatedToken(nullptr), _M_completeCount(0), _M_numTasks(0), _M_fHasExplicitToken(false)
6809 {
6810 }
6811 ~_RunAnyParam()
6812 {
6813 if (_CancellationTokenState::_IsValid(_M_exceptionRelatedToken))
6814 _M_exceptionRelatedToken->_Release();
6815 }
6816 task_completion_event<_CompletionType> _M_Completed;
6817 cancellation_token_source _M_cancellationSource;
6818 _CancellationTokenState * _M_exceptionRelatedToken;
6819 atomic_size_t _M_completeCount;
6820 size_t _M_numTasks;
6821 bool _M_fHasExplicitToken;
6822 };
6823
6824 template<typename _CompletionType, typename _Function, typename _TaskType>
6825 void _WhenAnyContinuationWrapper(_RunAnyParam<_CompletionType> * _PParam, const _Function & _Func, task<_TaskType>& _Task)
6826 {
6827 bool _IsTokenCancled = !_PParam->_M_fHasExplicitToken && _Task._GetImpl()->_M_pTokenState != _CancellationTokenState::_None() && _Task._GetImpl()->_M_pTokenState->_IsCanceled();
6828 if (_Task._GetImpl()->_IsCompleted() && !_IsTokenCancled)
6829 {
6830 _Func();
6831 if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6832 {
6833 delete _PParam;
6834 }
6835 }
6836 else
6837 {
6838 _ASSERTE(_Task._GetImpl()->_IsCanceled() || _IsTokenCancled);
6839 if (_Task._GetImpl()->_HasUserException() && !_IsTokenCancled)
6840 {
6841 if (_PParam->_M_Completed._StoreException(_Task._GetImpl()->_GetExceptionHolder()))
6842 {
6843 // This can only enter once.
6844 _PParam->_M_exceptionRelatedToken = _Task._GetImpl()->_M_pTokenState;
6845 _ASSERTE(_PParam->_M_exceptionRelatedToken);
6846 // Deref token will be done in the _PParam destructor.
6847 if (_PParam->_M_exceptionRelatedToken != _CancellationTokenState::_None())
6848 {
6849 _PParam->_M_exceptionRelatedToken->_Reference();
6850 }
6851 }
6852 }
6853
6854 if (atomic_increment(_PParam->_M_completeCount) == _PParam->_M_numTasks)
6855 {
6856 // If no one has be completed so far, we need to make some final cancellation decision.
6857 if (!_PParam->_M_Completed._IsTriggered())
6858 {
6859 // If we already explicit token, we can skip the token join part.
6860 if (!_PParam->_M_fHasExplicitToken)
6861 {
6862 if (_PParam->_M_exceptionRelatedToken)
6863 {
6864 _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PParam->_M_exceptionRelatedToken);
6865 }
6866 else
6867 {
6868 // If haven't captured any exception token yet, there was no exception for all those tasks,
6869 // so just pick a random token (current one) for normal cancellation.
6870 _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Task._GetImpl()->_M_pTokenState);
6871 }
6872 }
6873 // Do exception cancellation or normal cancellation based on whether it has stored exception.
6874 _PParam->_M_Completed._Cancel();
6875 }
6876 delete _PParam;
6877 }
6878 }
6879 }
6880
6881 template<typename _ElementType, typename _Iterator>
6882 struct _WhenAnyImpl
6883 {
6884 static task<std::pair<_ElementType, size_t>> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6885 {
6886 if( _Begin == _End )
6887 {
6888 throw invalid_operation("when_any(begin, end) cannot be called on an empty container.");
6889 }
6890 _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6891 auto _PParam = new _RunAnyParam<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>>();
6892
6893 if (_PTokenState)
6894 {
6895 _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
6896 _PParam->_M_fHasExplicitToken = true;
6897 }
6898
6899 task_options _Options(_TaskOptions);
6900 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
6901 task<std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
6902
6903 // Keep a copy ref to the token source
6904 auto _CancellationSource = _PParam->_M_cancellationSource;
6905
6906 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
6907 size_t _Index = 0;
6908 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6909 {
6910 if (_PTask->is_apartment_aware())
6911 {
6912 _Any_tasks_completed._SetAsync();
6913 }
6914
6915 _PTask->_Then([_PParam, _Index](task<_ElementType> _ResultTask) {
6916 auto _PParamCopy = _PParam; // Dev10
6917 auto _IndexCopy = _Index; // Dev10
6918 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
6919 _PParamCopy->_M_Completed.set(std::make_pair(std::make_pair(_ResultTask._GetImpl()->_GetResult(), _IndexCopy), _ResultTask._GetImpl()->_M_pTokenState));
6920 };
6921
6922 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
6923 }, _CancellationTokenState::_None());
6924
6925 _Index++;
6926 }
6927
6928 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
6929 return _Any_tasks_completed._Then([=](std::pair<std::pair<_ElementType, size_t>, _CancellationTokenState *> _Result) -> std::pair<_ElementType, size_t> {
6930 _ASSERTE(_Result.second);
6931 if (!_PTokenState)
6932 {
6933 _JoinAllTokens_Add(_CancellationSource, _Result.second);
6934 }
6935 return _Result.first;
6936 }, nullptr);
6937 }
6938 };
6939
6940 template<typename _Iterator>
6941 struct _WhenAnyImpl<void, _Iterator>
6942 {
6943 static task<size_t> _Perform(const task_options& _TaskOptions, _Iterator _Begin, _Iterator _End)
6944 {
6945 if( _Begin == _End )
6946 {
6947 throw invalid_operation("when_any(begin, end) cannot be called on an empty container.");
6948 }
6949
6950 _CancellationTokenState *_PTokenState = _TaskOptions.has_cancellation_token() ? _TaskOptions.get_cancellation_token()._GetImplValue() : nullptr;
6951 auto _PParam = new _RunAnyParam<std::pair<size_t, _CancellationTokenState *>>();
6952
6953 if (_PTokenState)
6954 {
6955 _JoinAllTokens_Add(_PParam->_M_cancellationSource, _PTokenState);
6956 _PParam->_M_fHasExplicitToken = true;
6957 }
6958
6959 task_options _Options(_TaskOptions);
6960 _Options.set_cancellation_token(_PParam->_M_cancellationSource.get_token());
6961 task<std::pair<size_t, _CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _Options);
6962
6963 // Keep a copy ref to the token source
6964 auto _CancellationSource = _PParam->_M_cancellationSource;
6965
6966 _PParam->_M_numTasks = static_cast<size_t>(std::distance(_Begin, _End));
6967 size_t _Index = 0;
6968 for (auto _PTask = _Begin; _PTask != _End; ++_PTask)
6969 {
6970 if (_PTask->is_apartment_aware())
6971 {
6972 _Any_tasks_completed._SetAsync();
6973 }
6974
6975 _PTask->_Then([_PParam, _Index](task<void> _ResultTask) {
6976 auto _PParamCopy = _PParam; // Dev10
6977 auto _IndexCopy = _Index; // Dev10
6978 auto _Func = [&_ResultTask, _PParamCopy, _IndexCopy]() {
6979 _PParamCopy->_M_Completed.set(std::make_pair(_IndexCopy, _ResultTask._GetImpl()->_M_pTokenState));
6980 };
6981 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
6982 }, _CancellationTokenState::_None());
6983
6984 _Index++;
6985 }
6986
6987 // All _Any_tasks_completed._SetAsync() must be finished before this return continuation task being created.
6988 return _Any_tasks_completed._Then([=](std::pair<size_t, _CancellationTokenState *> _Result) -> size_t {
6989 _ASSERTE(_Result.second);
6990 if (!_PTokenState)
6991 {
6992 _JoinAllTokens_Add(_CancellationSource, _Result.second);
6993 }
6994 return _Result.first;
6995 }, nullptr);
6996 }
6997 };
6998 } // namespace details
6999
7019
7020 template<typename _Iterator>
7021 auto when_any(_Iterator _Begin, _Iterator _End, const task_options& _TaskOptions = task_options())
7022 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_TaskOptions, _Begin, _End))
7023 {
7024 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
7025 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_TaskOptions, _Begin, _End);
7026 }
7027
7051
7052 template<typename _Iterator>
7053 auto when_any(_Iterator _Begin, _Iterator _End, cancellation_token _CancellationToken)
7054 -> decltype (details::_WhenAnyImpl<typename std::iterator_traits<_Iterator>::value_type::result_type, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End))
7055 {
7056 typedef typename std::iterator_traits<_Iterator>::value_type::result_type _ElementType;
7057 return details::_WhenAnyImpl<_ElementType, _Iterator>::_Perform(_CancellationToken._GetImplValue(), _Begin, _End);
7058 }
7059
7085
7086 template<typename _ReturnType>
7087 task<_ReturnType> operator||(const task<_ReturnType> & _Lhs, const task<_ReturnType> & _Rhs)
7088 {
7089 auto _PParam = new details::_RunAnyParam<std::pair<_ReturnType, size_t>>();
7090
7091 task<std::pair<_ReturnType, size_t>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7092 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7093 // So that _PParam can be used before it getting deleted.
7094 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<_ReturnType, size_t> _Ret) -> _ReturnType {
7095 _ASSERTE(_Ret.second);
7096 _JoinAllTokens_Add(_PParam->_M_cancellationSource, reinterpret_cast<details::_CancellationTokenState *>(_Ret.second));
7097 return _Ret.first;
7098 }, nullptr);
7099
7100 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7101 {
7102 _ReturnTask._SetAsync();
7103 }
7104
7105 _PParam->_M_numTasks = 2;
7106 auto _Continuation = [_PParam](task<_ReturnType> _ResultTask) {
7107 // Dev10 compiler bug
7108 auto _PParamCopy = _PParam;
7109 auto _Func = [&_ResultTask, _PParamCopy]() {
7110 _PParamCopy->_M_Completed.set(std::make_pair(_ResultTask._GetImpl()->_GetResult(), reinterpret_cast<size_t>(_ResultTask._GetImpl()->_M_pTokenState)));
7111 };
7112 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7113 };
7114
7115 _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());
7116 _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());
7117
7118 return _ReturnTask;
7119 }
7120
7146
7147 template<typename _ReturnType>
7148 task<std::vector<_ReturnType>> operator||(const task<std::vector<_ReturnType>> & _Lhs, const task<_ReturnType> & _Rhs)
7149 {
7150 auto _PParam = new details::_RunAnyParam<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>>();
7151
7152 task<std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *>> _Any_tasks_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7153
7154 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7155 // So that _PParam can be used before it getting deleted.
7156 auto _ReturnTask = _Any_tasks_completed._Then([=](std::pair<std::vector<_ReturnType>, details::_CancellationTokenState *> _Ret) -> std::vector<_ReturnType> {
7157 _ASSERTE(_Ret.second);
7158 _JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
7159 return _Ret.first;
7160 }, nullptr);
7161
7162 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7163 {
7164 _ReturnTask._SetAsync();
7165 }
7166
7167 _PParam->_M_numTasks = 2;
7168 _Lhs._Then([_PParam](task<std::vector<_ReturnType>> _ResultTask) {
7169 // Dev10 compiler bug
7170 auto _PParamCopy = _PParam;
7171 auto _Func = [&_ResultTask, _PParamCopy]() {
7172 auto _Result = _ResultTask._GetImpl()->_GetResult();
7173 _PParamCopy->_M_Completed.set(std::make_pair(_Result, _ResultTask._GetImpl()->_M_pTokenState));
7174 };
7175 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7176 }, details::_CancellationTokenState::_None());
7177
7178
7179 _Rhs._Then([_PParam](task<_ReturnType> _ResultTask)
7180 {
7181 auto _PParamCopy = _PParam;
7182 auto _Func = [&_ResultTask, _PParamCopy]() {
7183 auto _Result = _ResultTask._GetImpl()->_GetResult();
7184
7185 std::vector<_ReturnType> _Vec;
7186 _Vec.push_back(_Result);
7187 _PParamCopy->_M_Completed.set(std::make_pair(_Vec, _ResultTask._GetImpl()->_M_pTokenState));
7188 };
7189 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7190 }, details::_CancellationTokenState::_None());
7191
7192 return _ReturnTask;
7193 }
7194
7220
7221 template<typename _ReturnType>
7222 task<std::vector<_ReturnType>> operator||(const task<_ReturnType> & _Lhs, const task<std::vector<_ReturnType>> & _Rhs)
7223 {
7224 return _Rhs || _Lhs;
7225 }
7226
7252
7253 inline task<void> operator||(const task<void> & _Lhs, const task<void> & _Rhs)
7254 {
7255 auto _PParam = new details::_RunAnyParam<std::pair<details::_Unit_type, details::_CancellationTokenState *>>();
7256
7257 task<std::pair<details::_Unit_type, details::_CancellationTokenState *>> _Any_task_completed(_PParam->_M_Completed, _PParam->_M_cancellationSource.get_token());
7258 // Chain the return continuation task here to ensure it will get inline execution when _M_Completed.set is called,
7259 // So that _PParam can be used before it getting deleted.
7260 auto _ReturnTask = _Any_task_completed._Then([=](std::pair<details::_Unit_type, details::_CancellationTokenState *> _Ret) {
7261 _ASSERTE(_Ret.second);
7262 details::_JoinAllTokens_Add(_PParam->_M_cancellationSource, _Ret.second);
7263 }, nullptr);
7264
7265 if (_Lhs.is_apartment_aware() || _Rhs.is_apartment_aware())
7266 {
7267 _ReturnTask._SetAsync();
7268 }
7269
7270 _PParam->_M_numTasks = 2;
7271 auto _Continuation = [_PParam](task<void> _ResultTask) mutable {
7272 // Dev10 compiler needs this.
7273 auto _PParam1 = _PParam;
7274 auto _Func = [&_ResultTask, _PParam1]() {
7275 _PParam1->_M_Completed.set(std::make_pair(details::_Unit_type(), _ResultTask._GetImpl()->_M_pTokenState));
7276 };
7277 _WhenAnyContinuationWrapper(_PParam, _Func, _ResultTask);
7278 };
7279
7280 _Lhs._Then(_Continuation, details::_CancellationTokenState::_None());
7281 _Rhs._Then(_Continuation, details::_CancellationTokenState::_None());
7282
7283 return _ReturnTask;
7284 }
7285
7286 template<typename _Ty>
7287 task<_Ty> task_from_result(_Ty _Param, const task_options& _TaskOptions = task_options())
7288 {
7289 task_completion_event<_Ty> _Tce;
7290 _Tce.set(_Param);
7291 return create_task(_Tce, _TaskOptions);
7292 }
7293
7294 // Work around VS 2010 compiler bug
7295 #if _MSC_VER == 1600
7296 inline task<bool> task_from_result(bool _Param)
7297 {
7298 task_completion_event<bool> _Tce;
7299 _Tce.set(_Param);
7300 return create_task(_Tce, task_options());
7301 }
7302 #endif
7303 inline task<void> task_from_result(const task_options& _TaskOptions = task_options())
7304 {
7305 task_completion_event<void> _Tce;
7306 _Tce.set();
7307 return create_task(_Tce, _TaskOptions);
7308 }
7309
7310 template<typename _TaskType, typename _ExType>
7311 task<_TaskType> task_from_exception(_ExType _Exception, const task_options& _TaskOptions = task_options())
7312 {
7313 task_completion_event<_TaskType> _Tce;
7314 _Tce.set_exception(_Exception);
7315 return create_task(_Tce, _TaskOptions);
7316 }
7317
7318 namespace details
7319 {
7327 inline
7328 task<bool> do_while(std::function<task<bool>(void)> func)
7329 {
7330 task<bool> first = func();
7331 return first.then([=](bool guard) -> task<bool> {
7332 if (guard)
7333 return do_while(func);
7334 else
7335 return first;
7336 });
7337 }
7338
7339 } // namespace details
7340
7341 } // namespace Concurrency
7342
7343 #pragma pop_macro("new")
7344
7345 #if defined(_MSC_VER)
7346 #pragma warning(pop)
7347 #endif
7348 #pragma pack(pop)
7349
7350 #endif // (defined(_MSC_VER) && (_MSC_VER >= 1800))
7351
7352 #ifndef _CONCRT_H
7353 #ifndef _LWRCASE_CNCRRNCY
7354 #define _LWRCASE_CNCRRNCY
7355 // Note to reader: we're using lower-case namespace names everywhere, but the 'Concurrency' namespace
7356 // is capitalized for historical reasons. The alias let's us pretend that style issue doesn't exist.
7359 #endif
7360 #endif
7361
7362 #endif // _PPLXTASKS_H
bool _Cancel() const
Internal method to cancel the task_completion_event. Any task created using this event will be marked...
Definition: pplxtasks.h:2776
A generic RAII wrapper for locks that implements the critical_section interface cpprest_synchronizati...
Definition: pplxlinux.h:264
task_options(std::shared_ptr< _SchedType > _Scheduler)
Task option that specify a scheduler with shared lifetime
Definition: pplxtasks.h:1295
bool _StoreException(const std::shared_ptr< details::_ExceptionHolder > &_ExHolder) const
Method that stores an exception in the task completion event. This is used internally by when_any...
Definition: pplxtasks.h:2999
task_options(const task_options &_TaskOptions)
Task option copy constructor
Definition: pplxtasks.h:1331
void _SetAsync(bool _Async=true)
Sets a property determining whether the task is apartment aware.
Definition: pplxtasks.h:3666
Definition: pplxtasks.h:1436
The task_completion_event class allows you to delay the execution of a task until a condition is sati...
Definition: pplxtasks.h:2934
bool has_scheduler() const
Indicates whether a scheduler n was specified by the user
Definition: pplxtasks.h:1384
task()
Constructs a task object.
Definition: pplxtasks.h:4204
void _ScheduleTask(_UnrealizedChore_t *_PTaskHandle, _TaskInliningMode_t _InliningMode)
Helper function to schedule the task on the Task Collection.
Definition: pplxtasks.h:1979
The pplx namespace provides classes and functions that give you access to the Concurrency Runtime...
Definition: pplx.h:81
void result_type
The type of the result an object of this class produces.
Definition: pplxtasks.h:4180
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:3512
Definition: pplxtasks.h:1588
task & operator=(task &&_Other)
Replaces the contents of one task object with another.
Definition: pplxtasks.h:3396
Callstack container, which is used to capture and preserve callstacks in ppltasks. Members of this class is examined by vc debugger, thus there will be no public access methods. Please note that names of this class should be kept stable for debugger examining.
Definition: pplxtasks.h:257
void _SetImpl(const typename details::_Task_ptr< _ReturnType >::_Type &_Impl)
Set the implementation of the task to be the supplied implementaion.
Definition: pplxtasks.h:3648
__declspec(noinline) auto then(const _Function &_Func) const -> typename details::_ContinuationTypeTraits< _Function, _ReturnType >::_TaskOfType
Adds a continuation task to this task.
Definition: pplxtasks.h:3426
task(const task &_Other)
Constructs a task object.
Definition: pplxtasks.h:3336
bool _Cancel(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint=details::_TaskCreationCallstack()) const
Internal method to cancel the task_completion_event with the exception provided. Any task created usi...
Definition: pplxtasks.h:2787
Definition: pplxtasks.h:832
_PPLXIMP std::shared_ptr< pplx::scheduler_interface > _pplx_cdecl get_ambient_scheduler()
Gets the ambient scheduler to be used by the PPL constructs
Definition: pplxtasks.h:2593
struct __declspec(novtable) scheduler_interface
Scheduler Interface
Definition: pplxinterface.h:64
void _CreateImpl(details::_CancellationTokenState *_Ct, scheduler_ptr _Scheduler)
Create an underlying task implementation.
Definition: pplxtasks.h:4509
Definition: pplxtasks.h:297
static task_continuation_context use_default()
Creates the default task continuation context.
Definition: pplxtasks.h:1152
Definition: pplxtasks.h:324
auto _Then(const _Function &_Func, details::_CancellationTokenState *_PTokenState, details::_TaskInliningMode_t _InliningMode=details::_ForceInline) const -> typename details::_ContinuationTypeTraits< _Function, void >::_TaskOfType
An internal version of then that takes additional flags and executes the continuation inline...
Definition: pplxtasks.h:4558
bool _pplx_cdecl is_task_cancellation_requested()
Returns an indication of whether the task that is currently executing has received a request to cance...
Definition: pplxtasks.h:230
const details::_Task_ptr< _ReturnType >::_Type & _GetImpl() const
Return the underlying implementation for this task.
Definition: pplxtasks.h:3640
Definition: pplxtasks.h:581
The _PPLTaskHandle is the strong-typed task handle base. All user task functions need to be wrapped i...
Definition: pplxtasks.h:1621
virtual bool _CancelAndRunContinuations(bool _SynchronousCancel, bool _UserException, bool _PropagatedFromAncestor, const std::shared_ptr< _ExceptionHolder > &_ExceptionHolder_arg)
Requests cancellation on the task and schedules continuations if the task can be transitioned to a te...
Definition: pplxtasks.h:2426
void set_cancellation_token(cancellation_token _Token)
Sets the given token in the options
Definition: pplxtasks.h:1343
bool operator!=(const task< void > &_Rhs) const
Determines whether two task objects represent different internal tasks.
Definition: pplxtasks.h:4501
void _Cancel() const
Cancel the task_completion_event. Any task created using this event will be marked as canceled if it ...
Definition: pplxtasks.h:2980
__declspec(noinline) bool set_exception(std
Propagates an exception to all tasks associated with this event.
Definition: pplxtasks.h:2969
bool is_done() const
Determines if the task is completed.
Definition: pplxtasks.h:3558
Definition: pplxtasks.h:1599
Represents a pointer to a scheduler. This class exists to allow the the specification of a shared lif...
Definition: pplxinterface.h:74
void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
Sets a field in the task impl to the return callstack for calls to the task constructors and the then...
Definition: pplxtasks.h:4549
This class describes an exception thrown by the PPL tasks layer in order to force the current task to...
Definition: pplxcancellation_token.h:56
void _RunContinuation(_ContinuationTaskHandleBase *_PTaskHandle)
Function executes a continuation. This function is recorded by a parent task implementation when a co...
Definition: pplxtasks.h:2021
task_options(cancellation_token _Token)
Task option that specify a cancellation token
Definition: pplxtasks.h:1258
task & operator=(const task &_Other)
Replaces the contents of one task object with another.
Definition: pplxtasks.h:3376
void _SetImpl(const details::_Task_ptr< details::_Unit_type >::_Type &_Impl)
Set the implementation of the task to be the supplied implementaion.
Definition: pplxtasks.h:4525
Definition: pplxtasks.h:420
bool has_cancellation_token() const
Indicates whether a cancellation token was specified by the user
Definition: pplxtasks.h:1360
Definition: pplxtasks.h:293
task_options(scheduler_ptr _Scheduler)
Task option that specify a scheduler
Definition: pplxtasks.h:1319
Definition: pplxtasks.h:457
scheduler_ptr scheduler() const
Returns the scheduler for this task
Definition: pplxtasks.h:3574
Definition: pplxtasks.h:291
task_completion_event()
Constructs a task_completion_event object.
Definition: pplxtasks.h:2681
cancellation_token get_cancellation_token() const
Returns the cancellation token
Definition: pplxtasks.h:1368
task_options()
Default list of task creation options
Definition: pplxtasks.h:1246
Definition: pplxtasks.h:489
Definition: pplxtasks.h:426
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:176
bool set(_ResultType _Result) const
Sets the task completion event.
Definition: pplxtasks.h:2702
The tasks queued to the task_group or structured_task_group object completed successfully.
Definition: pplxinterface.h:143
Definition: pplxtasks.h:1426
Definition: pplxcancellation_token.h:256
The cancellation_token class represents the ability to determine whether some operation has been requ...
Definition: pplxcancellation_token.h:712
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:4426
Definition: pplxtasks.h:296
bool is_apartment_aware() const
Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such ...
Definition: pplxtasks.h:3591
Definition: pplxtasks.h:473
bool operator==(const task< void > &_Rhs) const
Determines whether two task objects represent the same internal task.
Definition: pplxtasks.h:4489
Definition: pplxtasks.h:510
Represents the allowed options for creating a task
Definition: pplxtasks.h:1238
task_options(scheduler_interface &_Scheduler)
Task option that specify a scheduler reference
Definition: pplxtasks.h:1307
bool operator!=(const task< _ReturnType > &_Rhs) const
Determines whether two task objects represent different internal tasks.
Definition: pplxtasks.h:3619
scheduler_ptr scheduler() const
Returns the scheduler for this task
Definition: pplxtasks.h:4465
Definition: pplxtasks.h:4671
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:4173
bool is_apartment_aware() const
Determines whether the task unwraps a Windows Runtime IAsyncInfo interface or is descended from such ...
Definition: pplxtasks.h:4477
bool _StoreException(_ExHolderType _ExHolder, const details::_TaskCreationCallstack &_SetExceptionAddressHint=details::_TaskCreationCallstack()) const
Internal method that stores an exception in the task completion event. This is used internally by whe...
Definition: pplxtasks.h:2808
Definition: pplxtasks.h:300
bool operator==(const task< _ReturnType > &_Rhs) const
Determines whether two task objects represent the same internal task.
Definition: pplxtasks.h:3607
const details::_Task_ptr< details::_Unit_type >::_Type & _GetImpl() const
Return the underlying implementation for this task.
Definition: pplxtasks.h:4517
_ReturnType result_type
The type of the result an object of this class produces.
Definition: pplxtasks.h:3185
static cancellation_token none()
Returns a cancellation token which can never be subject to cancellation.
Definition: pplxcancellation_token.h:724
Definition: astreambuf.h:37
task_continuation_context get_continuation_context() const
Returns the continuation context
Definition: pplxtasks.h:1376
bool _IsTriggered() const
Tests whether current event has been either Set, or Canceled.
Definition: pplxtasks.h:2824
void _SetImpl(typename details::_Task_ptr< _ReturnType >::_Type &&_Impl)
Set the implementation of the task to be the supplied implementaion using a move instead of a copy...
Definition: pplxtasks.h:3657
Definition: pplxtasks.h:4680
__declspec(noinline) bool set_exception(std
Propagates an exception to all tasks associated with this event.
Definition: pplxtasks.h:2765
Definition: pplxtasks.h:312
Definition: pplxtasks.h:156
void _Cancel(const std::shared_ptr< details::_ExceptionHolder > &_ExHolder) const
Cancel the task_completion_event with the exception holder provided. Any task created using this even...
Definition: pplxtasks.h:2989
auto _Then(const _Function &_Func, details::_CancellationTokenState *_PTokenState, details::_TaskInliningMode_t _InliningMode=details::_ForceInline) const -> typename details::_ContinuationTypeTraits< _Function, _ReturnType >::_TaskOfType
An internal version of then that takes additional flags and always execute the continuation inline by...
Definition: pplxtasks.h:3685
task_options(cancellation_token _Token, task_continuation_context _ContinuationContext)
Task option that specify a cancellation token and a continuation context. This is valid only for cont...
Definition: pplxtasks.h:1282
Definition: pplxtasks.h:1216
bool _IsTriggered() const
Test whether current event has been either Set, or Canceled.
Definition: pplxtasks.h:3007
task()
Constructs a task object.
Definition: pplxtasks.h:3209
Definition: pplxtasks.h:292
void _SetAsync(bool _Async=true)
Sets a property determining whether the task is apartment aware.
Definition: pplxtasks.h:4541
bool set() const
Sets the task completion event.
Definition: pplxtasks.h:2950
void _SetImpl(details::_Task_ptr< details::_Unit_type >::_Type &&_Impl)
Set the implementation of the task to be the supplied implementaion using a move instead of a copy...
Definition: pplxtasks.h:4533
Definition: pplxtasks.h:921
Definition: pplxtasks.h:295
task_group_status
Describes the execution status of a task_group or structured_task_group object. A value of this type ...
Definition: pplxinterface.h:130
__declspec(noinline) explicit task(_Ty _Param)
Constructs a task object.
Definition: pplxtasks.h:3251
scheduler_ptr get_scheduler() const
Returns the scheduler
Definition: pplxtasks.h:1392
void _SetTaskCreationCallstack(const details::_TaskCreationCallstack &_callstack)
Sets a field in the task impl to the return callstack for calls to the task constructors and the then...
Definition: pplxtasks.h:3674
task(task &&_Other)
Constructs a task object.
Definition: pplxtasks.h:3363
The implementation of a first-class task. This structure contains the task group used to execute the ...
Definition: pplxtasks.h:1423
void _ScheduleContinuation(_ContinuationTaskHandleBase *_PTaskHandle)
Schedule the actual continuation. This will either schedule the function on the continuation task's i...
Definition: pplxtasks.h:2124
Helper object used for LWT invocation.
Definition: pplxtasks.h:528
Definition: pplxcancellation_token.h:301
void _CreateImpl(details::_CancellationTokenState *_Ct, scheduler_ptr _Scheduler)
Create an underlying task implementation.
Definition: pplxtasks.h:3627
The task_group or structured_task_group object was canceled. One or more tasks may not have executed...
Definition: pplxinterface.h:149
The base implementation of a first-class task. This class contains all the non-type specific implemen...
Definition: pplxtasks.h:1688
The task_continuation_context class allows you to specify where you would like a continuation to be e...
Definition: pplxtasks.h:1131
The task_completion_event class allows you to delay the execution of a task until a condition is sati...
Definition: pplxtasks.h:2674
task_group_status task_status
A type that represents the terminal state of a task. Valid values are completed and canceled...
Definition: pplxtasks.h:174
task_options(task_continuation_context _ContinuationContext)
Task option that specify a continuation context. This is valid only for continuations (then) ...
Definition: pplxtasks.h:1270
This class describes an exception thrown when an invalid operation is performed that is not more accu...
Definition: pplxcancellation_token.h:99
void set_continuation_context(task_continuation_context _ContinuationContext)
Sets the given continuation context in the options
Definition: pplxtasks.h:1352
Definition: pplxtasks.h:294
bool is_done() const
Determines if the task is completed.
Definition: pplxtasks.h:4454