STLdoc
STLdocumentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
pplawait.h
Go to the documentation of this file.
1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 *
6 * ==--==
7 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
8 *
9 * pplawait.h
10 *
11 * Await Compiler Support for Parallel Patterns Library - PPL Tasks
12 *
13 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
14 ****/
15 
16 #pragma once
17 
18 #ifndef _PPLAWAIT_H
19 #define _PPLAWAIT_H
20 
21 #include <experimental/resumable>
22 #include <ppltasks.h>
23 #include <allocators>
24 #include <type_traits>
25 #include <ppltaskscheduler.h>
26 #include <utility>
27 
28 #define __resumable
29 
30 namespace std
31 {
32  namespace experimental
33  {
34  template <typename _Ty, typename... _Whatever>
35  struct coroutine_traits< ::concurrency::task<_Ty>, _Whatever...>
36  {
37  struct promise_type
38  {
39  auto get_return_object() const
40  {
41  return ::concurrency::create_task(_M_tce);
42  }
43 
44  bool initial_suspend() const { return (false); }
45 
46  bool final_suspend() const { return (false); }
47 
48  void return_value(const _Ty &_Val)
49  {
50  _M_tce.set(_Val);
51  }
52 
53  void set_exception(const exception_ptr &_Ptr)
54  {
55  _M_tce.set_exception(_Ptr);
56  }
57  private:
58  ::concurrency::task_completion_event<_Ty> _M_tce;
59  };
60  };
61 
62  template <typename... _Whatever>
63  struct coroutine_traits< ::concurrency::task<void>, _Whatever...>
64  {
65  struct promise_type
66  {
67  auto get_return_object() const
68  {
69  return ::concurrency::create_task(_M_tce);
70  }
71 
72  bool initial_suspend() const { return (false); }
73 
74  bool final_suspend() const { return (false); }
75 
76  void return_void()
77  {
78  _M_tce.set();
79  }
80 
81  void set_exception(const exception_ptr &_Ptr)
82  {
83  _M_tce.set_exception(_Ptr);
84  }
85  private:
86  ::concurrency::task_completion_event<void> _M_tce;
87  };
88  };
89 
90 
91  namespace details {
92  namespace awaitabletraitsimpl
93  {
94  template <typename _Ty>
95  inline bool _TryAwaitReady(_Ty & _Obj, decltype(std::declval<_Ty>().await_ready(), 0), int)
96  {
97  return _Obj.await_ready();
98  }
99  template <typename _Ty>
100  inline bool _TryAwaitReady(_Ty & _Obj, decltype(await_ready(std::declval<_Ty>()), 0), ...)
101  {
102  return await_ready(_Obj);
103  }
104 
105  template <typename _Ty, typename _Handle>
106  inline void _TryAwaitSuspend(_Ty & _Obj, _Handle _Hnd, decltype(std::declval<_Ty>().await_suspend(std::declval<_Handle>()), 0), int)
107  {
108  _Obj.await_suspend(_Hnd);
109  }
110  template <typename _Ty, typename _Handle>
111  inline void _TryAwaitSuspend(_Ty & _Obj, _Handle _Hnd, decltype(await_suspend(std::declval<_Ty>(), std::declval<_Handle>()), 0), ...)
112  {
113  await_suspend(_Obj, _Hnd);
114  }
115 
116  template <typename _Ty>
117  inline auto _TryAwaitResume(_Ty & _Obj, decltype(std::declval<_Ty>().await_resume(), 0), int)
118  {
119  return _Obj.await_resume();
120  }
121  template <typename _Ty>
122  inline auto _TryAwaitResume(_Ty & _Obj, decltype(await_resume(std::declval<_Ty>()), 0), ...)
123  {
124  return await_resume(_Obj);
125  }
126 
127  template <typename _Ty>
128  inline std::true_type _TryAwaitable(_Ty,
129  decltype(_TryAwaitReady(std::declval<std::decay_t<_Ty>>(), 0, 0), _TryAwaitSuspend(std::declval<std::decay_t<_Ty>>(), std::experimental::coroutine_handle<>(), 0, 0), _TryAwaitResume(std::declval<std::decay_t<_Ty>>(), 0, 0), 0));
130  inline std::false_type _TryAwaitable(...);
131 
132  }
133  }
134 
135  // Traits for
136  // 1. detecting a type whether satisfy awaitable contract requirement
137  // 2. invoking its awaitable contract methods
138 
139  template <typename _Ty>
140  struct awaitable_traits : public decltype(details::awaitabletraitsimpl::_TryAwaitable(std::declval<_Ty>(), 0))
141  {
142  static bool invoke_await_ready(_Ty & _Obj)
143  {
145  }
146 
147  template <typename _Handle>
148  static void invoke_await_suspend(_Ty &_Obj, _Handle _Hnd)
149  {
151  }
152 
153  static auto invoke_await_resume(_Ty &_Obj)
154  {
156  }
157  };
158 
159  template <typename _Ty>
161 
162  template <typename _Ty>
164 
165  }
166 }
167 
168 namespace Concurrency
169 {
170  // PPLTask awaitable extension
171 
172  template <class _Ty>
173  bool await_ready(const task<_Ty> & _Task)
174  {
175  return _Task.is_done();
176  }
177 
178  template <class _Ty, typename _Handle>
179  void await_suspend(task<_Ty> & _Task, _Handle _ResumeCb)
180  {
181  _Task.then([_ResumeCb](task<_Ty>&)
182  {
183  _ResumeCb();
185  }
186 
187  template <class _Ty>
188  auto await_resume(const task<_Ty> & _Task)
189  {
190  return _Task.get();
191  }
192 
193 
195  {
197  {
199  static void __cdecl _ChoreCallback(void *_TpTask)
200  {
201  auto _Context = static_cast<ThreadpoolContext*>(_TpTask);
202  _Context->_M_func();
203  }
204  std::function<void()> _M_func;
205  public:
206  template <typename _Handle>
207  void _CallInContext(_Handle _Hnd)
208  {
209  _M_func = _Hnd;
211  _M_chore._M_data = this;
212  details::_Schedule_chore(&_M_chore);
213  }
214 
216  {
217  _M_chore._M_work = nullptr;
218  }
219 
221  {
222  // Release chore multiple times is fine
223  details::_Release_chore(&_M_chore);
224  }
225  };
226 
229 
230  public:
232  {
233  await_resume_context _Context;
235  return _Context;
236  }
237 
239  {
240  return await_resume_context{};
241  }
242 
243  template <typename _Ty>
245  {
248  public:
249 
250  _CallbackChain(const _Ty &_Awaitable, await_resume_context *_ContextPtr) : _M_awaitable(_Awaitable), _M_contextPtr(_ContextPtr) { }
251 
252  bool await_ready() { return false; }
253 
254  template <typename _Handle>
255  void await_suspend(_Handle _Hnd)
256  {
258  if (_M_contextPtr->_M_context == details::_ContextCallback())
259  {
260  _M_contextPtr->_M_defaultContext._CallInContext([=] {
261  _Hnd();
262  });
263  }
264  else
265  {
266  _M_contextPtr->_M_context._CallInContext([=] {
267  _Hnd();
268  });
269  }
270  });
271  }
272 
274  {
276  }
277  };
278 
279  class _Callback
280  {
282  public:
283 
284  _Callback(await_resume_context * _ContextPtr) : _M_contextPtr(_ContextPtr) { }
285 
286  bool await_ready() { return false; }
287 
288  template <typename _Handle>
289  void await_suspend(_Handle _Hnd)
290  {
291  if (_M_contextPtr->_M_context == details::_ContextCallback())
292  {
293  _M_contextPtr->_M_defaultContext._CallInContext([=] {
294  _Hnd();
295  });
296  }
297  else
298  {
299  _M_contextPtr->_M_context._CallInContext([=] {
300  _Hnd();
301  });
302  }
303 
304  }
305 
306  void await_resume() { }
307  };
308 
309  template <typename _Ty>
310  auto get_awaitable(_Ty _Awaitable)
311  {
312  return _CallbackChain<std::decay_t<_Ty>>(_Awaitable, this);
313  }
314 
316  {
317  return _Callback(this);
318  }
319  };
320 }
321 
322 #ifdef __cplusplus_winrt
323 
324 // WinRT IAsync(Operation|Action) awaitable extension
325 
326 namespace Windows
327 {
328  namespace Foundation
329  {
330  inline bool await_ready(IAsyncInfo^ _Task)
331  {
332  return _Task->Status >= AsyncStatus::Completed;
333  }
334 
335  template <typename _Handle>
336  void await_suspend(IAsyncAction^ _Task, _Handle _ResumeCb)
337  {
338  _Task->Completed = ref new AsyncActionCompletedHandler(
339  [_ResumeCb](IAsyncAction^, AsyncStatus) { _ResumeCb(); }, ::Platform::CallbackContext::Same);
340  }
341 
342  template <typename _Ty, typename _Handle>
343  void await_suspend(IAsyncOperation<_Ty>^ _Task, _Handle _ResumeCb)
344  {
345  _Task->Completed = ref new AsyncOperationCompletedHandler<_Ty>(
346  [_ResumeCb](IAsyncOperation<_Ty>^, AsyncStatus) { _ResumeCb(); }, ::Platform::CallbackContext::Same);
347  }
348 
349  template <typename _Pr, typename _Handle>
350  void await_suspend(IAsyncActionWithProgress<_Pr>^ _Task, _Handle _ResumeCb)
351  {
352  _Task->Completed = ref new AsyncActionWithProgressCompletedHandler<_Pr>(
353  [_ResumeCb](IAsyncActionWithProgress<_Pr>^, AsyncStatus) { _ResumeCb(); }, ::Platform::CallbackContext::Same);
354  }
355 
356  template <typename _Ty, typename _Pr, typename _Handle>
357  void await_suspend(IAsyncOperationWithProgress<_Ty, _Pr>^ _Task, _Handle _ResumeCb)
358  {
359  _Task->Completed = ref new AsyncOperationWithProgressCompletedHandler<_Ty, _Pr>(
360  [_ResumeCb](IAsyncOperationWithProgress<_Ty, _Pr>^, AsyncStatus) { _ResumeCb(); }, ::Platform::CallbackContext::Same);
361  }
362 
363  // When GetResults is called for an operation in the Canceled state, an E_ILLEGAL_METHOD_CALL exception will be thrown.
364  // We preempt that by throwing an OperationCanceled exception, which better meets caller expectations.
365  inline void _VerifyStateForResultsCall(Windows::Foundation::AsyncStatus status)
366  {
367  if (status == AsyncStatus::Canceled)
368  {
369  throw ::Platform::Exception::CreateException(E_ABORT);
370  }
371  }
372 
373  inline void await_resume(Windows::Foundation::IAsyncAction^ _Task)
374  {
375  _VerifyStateForResultsCall(_Task->Status);
376  _Task->GetResults();
377  }
378 
379  template <typename _Ty>
380  _Ty await_resume(Windows::Foundation::IAsyncOperation<_Ty>^ _Task)
381  {
382  _VerifyStateForResultsCall(_Task->Status);
383  return _Task->GetResults();
384  }
385 
386  template <typename _Pr>
387  void await_resume(Windows::Foundation::IAsyncActionWithProgress<_Pr>^ _Task)
388  {
389  _VerifyStateForResultsCall(_Task->Status);
390  _Task->GetResults();
391  }
392 
393  template <typename _Ty, typename _Pr>
394  _Ty await_resume(Windows::Foundation::IAsyncOperationWithProgress<_Ty, _Pr>^ _Task)
395  {
396  _VerifyStateForResultsCall(_Task->Status);
397  return _Task->GetResults();
398  }
399  }
400 }
401 
402 #endif // __cplusplus_winrt
403 #endif // _PPLAWAIT_H
_Threadpool_callback _M_callback
Definition: ppltaskscheduler.h:29
void await_resume()
Definition: pplawait.h:306
auto get_awaitable(_Ty _Awaitable)
Definition: pplawait.h:310
void _TryAwaitSuspend(_Ty &_Obj, _Handle _Hnd, decltype(std::declval< _Ty >().await_suspend(std::declval< _Handle >()), 0), int)
Definition: pplawait.h:106
auto get_awaitable()
Definition: pplawait.h:315
details::_ContextCallback _M_context
Definition: pplawait.h:227
reference_wrapper< _Ty > ref(_Ty &_Val) _NOEXCEPT
Definition: type_traits:1617
_CRTIMP2 void __cdecl _Release_chore(_Threadpool_chore *)
static void invoke_await_suspend(_Ty &_Obj, _Handle _Hnd)
Definition: pplawait.h:148
auto await_resume(const task< _Ty > &_Task)
Definition: pplawait.h:188
auto _TryAwaitResume(_Ty &_Obj, decltype(std::declval< _Ty >().await_resume(), 0), int)
Definition: pplawait.h:117
void await_suspend(task< _Ty > &_Task, _Handle _ResumeCb)
Definition: pplawait.h:179
Definition: exception:254
await_resume_context * _M_contextPtr
Definition: pplawait.h:281
void _CallInContext(_Handle _Hnd)
Definition: pplawait.h:207
_In_ int _Val
Definition: vcruntime_string.h:62
await_resume_context * _M_contextPtr
Definition: pplawait.h:247
static task_continuation_context get_current_winrt_context()
Returns a task continuation context object that represents the current winrt thread context...
Definition: ppltasks.h:955
file_status status(const path &)
Definition: filesystem:3137
auto await_resume()
Definition: pplawait.h:273
STL namespace.
void await_suspend(_Handle _Hnd)
Definition: pplawait.h:289
The Concurrency namespace provides classes and functions that provide access to the Concurrency Runti...
Definition: agents.h:43
bool _TryAwaitReady(_Ty &_Obj, decltype(std::declval< _Ty >().await_ready(), 0), int)
Definition: pplawait.h:95
static bool invoke_await_ready(_Ty &_Obj)
Definition: pplawait.h:142
void * _M_work
Definition: ppltaskscheduler.h:28
std::function< void()> _M_func
Definition: pplawait.h:204
_CRTIMP2 int __cdecl _Schedule_chore(_Threadpool_chore *)
integral_constant< bool, false > false_type
Definition: xtr1common:41
Definition: ppltaskscheduler.h:26
_CRTIMP2 void __thiscall _CallInContext(_CallbackFunction _Func, bool _IgnoreDisconnect) const
::concurrency::task_completion_event< void > _M_tce
Definition: pplawait.h:86
bool is_done() const
Determines if the task is completed.
Definition: ppltasks.h:3288
static auto invoke_await_resume(_Ty &_Obj)
Definition: pplawait.h:153
bool await_ready(const task< _Ty > &_Task)
Definition: pplawait.h:173
_ReturnType get() const
Returns the result this task produced. If the task is not in a terminal state, a call to get will wai...
Definition: ppltasks.h:3264
Definition: vccorlib.h:117
static await_resume_context any()
Definition: pplawait.h:238
void await_suspend(_Handle _Hnd)
Definition: pplawait.h:255
ThreadpoolContext _M_defaultContext
Definition: pplawait.h:228
static _ContextCallback _CaptureCurrent()
Definition: ppltasks.h:502
Definition: deque:16
::concurrency::task_completion_event< _Ty > _M_tce
Definition: pplawait.h:58
_Ty _M_awaitable
Definition: pplawait.h:246
typename awaitable_traits< _Ty >::type is_awaitable_t
Definition: pplawait.h:163
std::true_type _TryAwaitable(_Ty, decltype(_TryAwaitReady(std::declval< std::decay_t< _Ty >>(), 0, 0), _TryAwaitSuspend(std::declval< std::decay_t< _Ty >>(), std::experimental::coroutine_handle<>(), 0, 0), _TryAwaitResume(std::declval< std::decay_t< _Ty >>(), 0, 0), 0))
Definition: ppltasks.h:496
_Callback(await_resume_context *_ContextPtr)
Definition: pplawait.h:284
bool await_ready()
Definition: pplawait.h:252
static await_resume_context current()
Definition: pplawait.h:231
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: ppltasks.h:85
Definition: pplawait.h:194
add_rvalue_reference< _Ty >::type declval() _NOEXCEPT
integral_constant< bool, true > true_type
Definition: xtr1common:40
details::_Threadpool_chore _M_chore
Definition: pplawait.h:198
static void __cdecl _ChoreCallback(void *_TpTask)
Definition: pplawait.h:199
bool await_ready()
Definition: pplawait.h:286
void * _M_data
Definition: ppltaskscheduler.h:30
Definition: pplawait.h:140
_CallbackChain(const _Ty &_Awaitable, await_resume_context *_ContextPtr)
Definition: pplawait.h:250