1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
7 //
8 // AsyncMethodBuilder.cs
9 //
10 // <OWNER>Microsoft</OWNER>
11 //
12 // Compiler-targeted types that build tasks for use as the return types of asynchronous methods.
13 //
14 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
15 
16 using System;
17 using System.Collections.Concurrent;
18 using System.Collections.Generic;
19 using System.Diagnostics;
20 using System.Diagnostics.CodeAnalysis;
21 using System.Diagnostics.Contracts;
22 using System.Runtime.ExceptionServices;
23 using System.Security;
24 using System.Security.Permissions;
25 using System.Threading;
26 using System.Threading.Tasks;
27 
28 #if FEATURE_COMINTEROP
29 using System.Runtime.InteropServices.WindowsRuntime;
30 #endif // FEATURE_COMINTEROP
31 
32 namespace System.Runtime.CompilerServices
33 {
34     /// <summary>
35     /// Provides a builder for asynchronous methods that return void.
36     /// This type is intended for compiler use only.
37     /// </summary>
38     [HostProtection(Synchronization = true, ExternalThreading = true)]
39     public struct AsyncVoidMethodBuilder
40     {
41         /// <summary>The synchronization context associated with this operation.</summary>
42         private SynchronizationContext m_synchronizationContext;
43         /// <summary>State related to the IAsyncStateMachine.</summary>
44         private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly
45         /// <summary>Task used for debugging and logging purposes only.  Lazily initialized.</summary>
46         private Task m_task;
47 
48         /// <summary>Initializes a new <see cref="AsyncVoidMethodBuilder"/>.</summary>
49         /// <returns>The initialized <see cref="AsyncVoidMethodBuilder"/>.</returns>
CreateSystem.Runtime.CompilerServices.AsyncVoidMethodBuilder50         public static AsyncVoidMethodBuilder Create()
51         {
52             // Capture the current sync context.  If there isn't one, use the dummy s_noContextCaptured
53             // instance; this allows us to tell the state of no captured context apart from the state
54             // of an improperly constructed builder instance.
55             SynchronizationContext sc = SynchronizationContext.CurrentNoFlow;
56             if (sc != null)
57                 sc.OperationStarted();
58             return new AsyncVoidMethodBuilder() { m_synchronizationContext = sc };
59         }
60 
61         /// <summary>Initiates the builder's execution with the associated state machine.</summary>
62         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
63         /// <param name="stateMachine">The state machine instance, passed by reference.</param>
64         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
65         [SecuritySafeCritical]
66         [DebuggerStepThrough]
67         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
68         {
69             // See comment on AsyncMethodBuilderCore.Start
70             // AsyncMethodBuilderCore.Start(ref stateMachine);
71 
72             if (stateMachine == null) throw new ArgumentNullException("stateMachine");
Contract.EndContractBlockSystem.Runtime.CompilerServices.AsyncVoidMethodBuilder73             Contract.EndContractBlock();
74 
75             // Run the MoveNext method within a copy-on-write ExecutionContext scope.
76             // This allows us to undo any ExecutionContext changes made in MoveNext,
77             // so that they won't "leak" out of the first await.
78 
79             ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
RuntimeHelpers.PrepareConstrainedRegionsSystem.Runtime.CompilerServices.AsyncVoidMethodBuilder80             RuntimeHelpers.PrepareConstrainedRegions();
81             try
82             {
83                 ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
84                 stateMachine.MoveNext();
85             }
86             finally
87             {
88                 ecs.Undo();
89             }
90         }
91 
92         /// <summary>Associates the builder with the state machine it represents.</summary>
93         /// <param name="stateMachine">The heap-allocated state machine object.</param>
94         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
95         /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
SetStateMachine(IAsyncStateMachine stateMachine)96         public void SetStateMachine(IAsyncStateMachine stateMachine)
97         {
98             m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
99         }
100 
101         /// <summary>
102         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
103         /// </summary>
104         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
105         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
106         /// <param name="awaiter">The awaiter.</param>
107         /// <param name="stateMachine">The state machine.</param>
108         public void AwaitOnCompleted<TAwaiter, TStateMachine>(
109             ref TAwaiter awaiter, ref TStateMachine stateMachine)
110             where TAwaiter : INotifyCompletion
111             where TStateMachine : IAsyncStateMachine
112         {
113             try
114             {
115                 AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
116                 var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
117                 Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");
118 
119                 // If this is our first await, such that we've not yet boxed the state machine, do so now.
120                 if (m_coreState.m_stateMachine == null)
121                 {
122                     if (AsyncCausalityTracer.LoggingOn)
123                         AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Task.Id, "Async: " + stateMachine.GetType().Name, 0);
124 
125                     // Box the state machine, then tell the boxed instance to call back into its own builder,
126                     // so we can cache the boxed reference.
127                     Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
128                     m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, null);
129                 }
130 
131                 awaiter.OnCompleted(continuation);
132             }
133             catch (Exception exc)
134             {
135                 // Prevent exceptions from leaking to the call site, which could
136                 // then allow multiple flows of execution through the same async method
137                 // if the awaiter had already scheduled the continuation by the time
138                 // the exception was thrown.  We propagate the exception on the
139                 // ThreadPool because we can trust it to not throw, unlike
140                 // if we were to go to a user-supplied SynchronizationContext,
141                 // whose Post method could easily throw.
142                 AsyncMethodBuilderCore.ThrowAsync(exc, targetContext: null);
143             }
144         }
145 
146         /// <summary>
147         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
148         /// </summary>
149         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
150         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
151         /// <param name="awaiter">The awaiter.</param>
152         /// <param name="stateMachine">The state machine.</param>
153         [SecuritySafeCritical]
154         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
155             ref TAwaiter awaiter, ref TStateMachine stateMachine)
156             where TAwaiter : ICriticalNotifyCompletion
157             where TStateMachine : IAsyncStateMachine
158         {
159             try
160             {
161                 AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
162                 var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
163                 Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");
164 
165                 // If this is our first await, such that we've not yet boxed the state machine, do so now.
166                 if (m_coreState.m_stateMachine == null)
167                 {
168                     if (AsyncCausalityTracer.LoggingOn)
169                         AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Task.Id, "Async: " + stateMachine.GetType().Name, 0);
170 
171                     // Box the state machine, then tell the boxed instance to call back into its own builder,
172                     // so we can cache the boxed reference.
173                     Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
174                     m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, null);
175                 }
176 
177                 awaiter.UnsafeOnCompleted(continuation);
178             }
179             catch (Exception e)
180             {
181                 AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
182             }
183         }
184 
185         /// <summary>Completes the method builder successfully.</summary>
SetResult()186         public void SetResult()
187         {
188             if (AsyncCausalityTracer.LoggingOn)
189                 AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Task.Id, AsyncCausalityStatus.Completed);
190 
191             if (m_synchronizationContext != null)
192             {
193                 NotifySynchronizationContextOfCompletion();
194             }
195         }
196 
197         /// <summary>Faults the method builder with an exception.</summary>
198         /// <param name="exception">The exception that is the cause of this fault.</param>
199         /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
200         /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
SetException(Exception exception)201         public void SetException(Exception exception)
202         {
203             if (exception == null) throw new ArgumentNullException("exception");
204             Contract.EndContractBlock();
205 
206             if (AsyncCausalityTracer.LoggingOn)
207                 AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Task.Id, AsyncCausalityStatus.Error);
208 
209             if (m_synchronizationContext != null)
210             {
211                 // If we captured a synchronization context, Post the throwing of the exception to it
212                 // and decrement its outstanding operation count.
213                 try
214                 {
215                     AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: m_synchronizationContext);
216                 }
217                 finally
218                 {
219                     NotifySynchronizationContextOfCompletion();
220                 }
221             }
222             else
223             {
224                 // Otherwise, queue the exception to be thrown on the ThreadPool.  This will
225                 // result in a crash unless legacy exception behavior is enabled by a config
226                 // file or a CLR host.
227                 AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: null);
228             }
229         }
230 
231         /// <summary>Notifies the current synchronization context that the operation completed.</summary>
NotifySynchronizationContextOfCompletion()232         private void NotifySynchronizationContextOfCompletion()
233         {
234             Contract.Assert(m_synchronizationContext != null, "Must only be used with a non-null context.");
235             try
236             {
237                 m_synchronizationContext.OperationCompleted();
238             }
239             catch (Exception exc)
240             {
241                 // If the interaction with the SynchronizationContext goes awry,
242                 // fall back to propagating on the ThreadPool.
243                 AsyncMethodBuilderCore.ThrowAsync(exc, targetContext: null);
244             }
245         }
246 
247         // This property lazily instantiates the Task in a non-thread-safe manner.
248         private Task Task
249         {
250             get
251             {
252                 if (m_task == null) m_task = new Task();
253                 return m_task;
254             }
255         }
256 
257         /// <summary>
258         /// Gets an object that may be used to uniquely identify this builder to the debugger.
259         /// </summary>
260         /// <remarks>
261         /// This property lazily instantiates the ID in a non-thread-safe manner.
262         /// It must only be used by the debugger and AsyncCausalityTracer in a single-threaded manner.
263         /// </remarks>
264         private object ObjectIdForDebugger { get { return this.Task; } }
265     }
266 
267     /// <summary>
268     /// Provides a builder for asynchronous methods that return <see cref="System.Threading.Tasks.Task"/>.
269     /// This type is intended for compiler use only.
270     /// </summary>
271     /// <remarks>
272     /// AsyncTaskMethodBuilder is a value type, and thus it is copied by value.
273     /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
274     /// or else the copies may end up building distinct Task instances.
275     /// </remarks>
276     [HostProtection(Synchronization = true, ExternalThreading = true)]
277     public struct AsyncTaskMethodBuilder
278     {
279         /// <summary>A cached VoidTaskResult task used for builders that complete synchronously.</summary>
280         private readonly static Task<VoidTaskResult> s_cachedCompleted = AsyncTaskMethodBuilder<VoidTaskResult>.s_defaultResultTask;
281 
282         /// <summary>The generic builder object to which this non-generic instance delegates.</summary>
283         private AsyncTaskMethodBuilder<VoidTaskResult> m_builder; // mutable struct: must not be readonly
284 
285         /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary>
286         /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns>
CreateAsyncTaskMethodBuilder287         public static AsyncTaskMethodBuilder Create()
288         {
289             return default(AsyncTaskMethodBuilder);
290             // Note: If ATMB<T>.Create is modified to do any initialization, this
291             //       method needs to be updated to do m_builder = ATMB<T>.Create().
292         }
293 
294         /// <summary>Initiates the builder's execution with the associated state machine.</summary>
295         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
296         /// <param name="stateMachine">The state machine instance, passed by reference.</param>
297         [SecuritySafeCritical]
298         [DebuggerStepThrough]
299         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
300         {
301             // See comment on AsyncMethodBuilderCore.Start
302             // AsyncMethodBuilderCore.Start(ref stateMachine);
303 
304             if (stateMachine == null) throw new ArgumentNullException("stateMachine");
Contract.EndContractBlockAsyncTaskMethodBuilder305             Contract.EndContractBlock();
306 
307             // Run the MoveNext method within a copy-on-write ExecutionContext scope.
308             // This allows us to undo any ExecutionContext changes made in MoveNext,
309             // so that they won't "leak" out of the first await.
310 
311             ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
RuntimeHelpers.PrepareConstrainedRegionsAsyncTaskMethodBuilder312             RuntimeHelpers.PrepareConstrainedRegions();
313             try
314             {
315                 ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
316                 stateMachine.MoveNext();
317             }
318             finally
319             {
320                 ecs.Undo();
321             }
322         }
323 
324         /// <summary>Associates the builder with the state machine it represents.</summary>
325         /// <param name="stateMachine">The heap-allocated state machine object.</param>
326         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
327         /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
SetStateMachine(IAsyncStateMachine stateMachine)328         public void SetStateMachine(IAsyncStateMachine stateMachine)
329         {
330             m_builder.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
331         }
332 
333         /// <summary>
334         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
335         /// </summary>
336         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
337         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
338         /// <param name="awaiter">The awaiter.</param>
339         /// <param name="stateMachine">The state machine.</param>
340         public void AwaitOnCompleted<TAwaiter, TStateMachine>(
341             ref TAwaiter awaiter, ref TStateMachine stateMachine)
342             where TAwaiter : INotifyCompletion
343             where TStateMachine : IAsyncStateMachine
344         {
345             m_builder.AwaitOnCompleted<TAwaiter, TStateMachine>(ref awaiter, ref stateMachine);
346         }
347 
348         /// <summary>
349         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
350         /// </summary>
351         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
352         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
353         /// <param name="awaiter">The awaiter.</param>
354         /// <param name="stateMachine">The state machine.</param>
355         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
356             ref TAwaiter awaiter, ref TStateMachine stateMachine)
357             where TAwaiter : ICriticalNotifyCompletion
358             where TStateMachine : IAsyncStateMachine
359         {
360             m_builder.AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref awaiter, ref stateMachine);
361         }
362 
363         /// <summary>Gets the <see cref="System.Threading.Tasks.Task"/> for this builder.</summary>
364         /// <returns>The <see cref="System.Threading.Tasks.Task"/> representing the builder's asynchronous operation.</returns>
365         /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
366         public Task Task { get { return m_builder.Task; } }
367 
368         /// <summary>
369         /// Completes the <see cref="System.Threading.Tasks.Task"/> in the
370         /// <see cref="System.Threading.Tasks.TaskStatus">RanToCompletion</see> state.
371         /// </summary>
372         /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
373         /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
SetResult()374         public void SetResult()
375         {
376             // Accessing AsyncTaskMethodBuilder.s_cachedCompleted is faster than
377             // accessing AsyncTaskMethodBuilder<T>.s_defaultResultTask.
378             m_builder.SetResult(s_cachedCompleted);
379         }
380 
381         /// <summary>
382         /// Completes the <see cref="System.Threading.Tasks.Task"/> in the
383         /// <see cref="System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
384         /// </summary>
385         /// <param name="exception">The <see cref="System.Exception"/> to use to fault the task.</param>
386         /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
387         /// <exception cref="System.InvalidOperationException">The builder is not initialized.</exception>
388         /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
SetException(Exception exception)389         public void SetException(Exception exception) { m_builder.SetException(exception); }
390 
391         /// <summary>
392         /// Called by the debugger to request notification when the first wait operation
393         /// (await, Wait, Result, etc.) on this builder's task completes.
394         /// </summary>
395         /// <param name="enabled">
396         /// true to enable notification; false to disable a previously set notification.
397         /// </param>
SetNotificationForWaitCompletion(bool enabled)398         internal void SetNotificationForWaitCompletion(bool enabled)
399         {
400             m_builder.SetNotificationForWaitCompletion(enabled);
401         }
402 
403         /// <summary>
404         /// Gets an object that may be used to uniquely identify this builder to the debugger.
405         /// </summary>
406         /// <remarks>
407         /// This property lazily instantiates the ID in a non-thread-safe manner.
408         /// It must only be used by the debugger and tracing pruposes, and only in a single-threaded manner
409         /// when no other threads are in the middle of accessing this property or this.Task.
410         /// </remarks>
411         private object ObjectIdForDebugger { get { return this.Task; } }
412     }
413 
414     /// <summary>
415     /// Provides a builder for asynchronous methods that return <see cref="System.Threading.Tasks.Task{TResult}"/>.
416     /// This type is intended for compiler use only.
417     /// </summary>
418     /// <remarks>
419     /// AsyncTaskMethodBuilder{TResult} is a value type, and thus it is copied by value.
420     /// Prior to being copied, one of its Task, SetResult, or SetException members must be accessed,
421     /// or else the copies may end up building distinct Task instances.
422     /// </remarks>
423     [HostProtection(Synchronization = true, ExternalThreading = true)]
424     public struct AsyncTaskMethodBuilder<TResult>
425     {
426         /// <summary>A cached task for default(TResult).</summary>
427         internal readonly static Task<TResult> s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult));
428 
429         // WARNING: For performance reasons, the m_task field is lazily initialized.
430         //          For correct results, the struct AsyncTaskMethodBuilder<TResult> must
431         //          always be used from the same location/copy, at least until m_task is
432         //          initialized.  If that guarantee is broken, the field could end up being
433         //          initialized on the wrong copy.
434 
435         /// <summary>State related to the IAsyncStateMachine.</summary>
436         private AsyncMethodBuilderCore m_coreState; // mutable struct: must not be readonly
437         /// <summary>The lazily-initialized built task.</summary>
438         private Task<TResult> m_task; // lazily-initialized: must not be readonly
439 
440         /// <summary>Initializes a new <see cref="AsyncTaskMethodBuilder"/>.</summary>
441         /// <returns>The initialized <see cref="AsyncTaskMethodBuilder"/>.</returns>
442         public static AsyncTaskMethodBuilder<TResult> Create()
443         {
444             return default(AsyncTaskMethodBuilder<TResult>);
445             // NOTE:  If this method is ever updated to perform more initialization,
446             //        ATMB.Create must also be updated to call this Create method.
447         }
448 
449         /// <summary>Initiates the builder's execution with the associated state machine.</summary>
450         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
451         /// <param name="stateMachine">The state machine instance, passed by reference.</param>
452         [SecuritySafeCritical]
453         [DebuggerStepThrough]
454         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
455         {
456             // See comment on AsyncMethodBuilderCore.Start
457             // AsyncMethodBuilderCore.Start(ref stateMachine);
458 
459             if (stateMachine == null) throw new ArgumentNullException("stateMachine");
460             Contract.EndContractBlock();
461 
462             // Run the MoveNext method within a copy-on-write ExecutionContext scope.
463             // This allows us to undo any ExecutionContext changes made in MoveNext,
464             // so that they won't "leak" out of the first await.
465 
466             ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
467             RuntimeHelpers.PrepareConstrainedRegions();
468             try
469             {
470                 ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
471                 stateMachine.MoveNext();
472             }
473             finally
474             {
475                 ecs.Undo();
476             }
477         }
478 
479         /// <summary>Associates the builder with the state machine it represents.</summary>
480         /// <param name="stateMachine">The heap-allocated state machine object.</param>
481         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
482         /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
483         public void SetStateMachine(IAsyncStateMachine stateMachine)
484         {
485             m_coreState.SetStateMachine(stateMachine); // argument validation handled by AsyncMethodBuilderCore
486         }
487 
488         /// <summary>
489         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
490         /// </summary>
491         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
492         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
493         /// <param name="awaiter">The awaiter.</param>
494         /// <param name="stateMachine">The state machine.</param>
495         public void AwaitOnCompleted<TAwaiter, TStateMachine>(
496             ref TAwaiter awaiter, ref TStateMachine stateMachine)
497             where TAwaiter : INotifyCompletion
498             where TStateMachine : IAsyncStateMachine
499         {
500             try
501             {
502                 AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
503                 var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
504                 Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");
505 
506                 // If this is our first await, such that we've not yet boxed the state machine, do so now.
507                 if (m_coreState.m_stateMachine == null)
508                 {
509                     // Force the Task to be initialized prior to the first suspending await so
510                     // that the original stack-based builder has a reference to the right Task.
511                     var builtTask = this.Task;
512 
513                     // Box the state machine, then tell the boxed instance to call back into its own builder,
514                     // so we can cache the boxed reference.
515                     Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
516                     m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask);
517                 }
518 
519                 awaiter.OnCompleted(continuation);
520             }
521             catch (Exception e)
522             {
523                 AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
524             }
525         }
526 
527         /// <summary>
528         /// Schedules the specified state machine to be pushed forward when the specified awaiter completes.
529         /// </summary>
530         /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
531         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
532         /// <param name="awaiter">The awaiter.</param>
533         /// <param name="stateMachine">The state machine.</param>
534         [SecuritySafeCritical]
535         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(
536             ref TAwaiter awaiter, ref TStateMachine stateMachine)
537             where TAwaiter : ICriticalNotifyCompletion
538             where TStateMachine : IAsyncStateMachine
539         {
540             try
541             {
542                 AsyncMethodBuilderCore.MoveNextRunner runnerToInitialize = null;
543                 var continuation = m_coreState.GetCompletionAction(AsyncCausalityTracer.LoggingOn ? this.Task : null, ref runnerToInitialize);
544                 Contract.Assert(continuation != null, "GetCompletionAction should always return a valid action.");
545 
546                 // If this is our first await, such that we've not yet boxed the state machine, do so now.
547                 if (m_coreState.m_stateMachine == null)
548                 {
549                     // Force the Task to be initialized prior to the first suspending await so
550                     // that the original stack-based builder has a reference to the right Task.
551                     var builtTask = this.Task;
552 
553                     // Box the state machine, then tell the boxed instance to call back into its own builder,
554                     // so we can cache the boxed reference.
555                     Contract.Assert(!Object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference");
556                     m_coreState.PostBoxInitialization(stateMachine, runnerToInitialize, builtTask);
557                 }
558 
559                 awaiter.UnsafeOnCompleted(continuation);
560             }
561             catch (Exception e)
562             {
563                 AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
564             }
565         }
566 
567         /// <summary>Gets the <see cref="System.Threading.Tasks.Task{TResult}"/> for this builder.</summary>
568         /// <returns>The <see cref="System.Threading.Tasks.Task{TResult}"/> representing the builder's asynchronous operation.</returns>
569         public Task<TResult> Task
570         {
571             get
572             {
573                 // Get and return the task. If there isn't one, first create one and store it.
574                 var task = m_task;
575                 if (task == null) { m_task = task = new Task<TResult>(); }
576                 return task;
577             }
578         }
579 
580         /// <summary>
581         /// Completes the <see cref="System.Threading.Tasks.Task{TResult}"/> in the
582         /// <see cref="System.Threading.Tasks.TaskStatus">RanToCompletion</see> state with the specified result.
583         /// </summary>
584         /// <param name="result">The result to use to complete the task.</param>
585         /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
586         public void SetResult(TResult result)
587         {
588             // Get the currently stored task, which will be non-null if get_Task has already been accessed.
589             // If there isn't one, get a task and store it.
590             var task = m_task;
591             if (task == null)
592             {
593                 m_task = GetTaskForResult(result);
594                 Contract.Assert(m_task != null, "GetTaskForResult should never return null");
595             }
596             // Slow path: complete the existing task.
597             else
598             {
599                 if (AsyncCausalityTracer.LoggingOn)
600                     AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, task.Id, AsyncCausalityStatus.Completed);
601 
602                 //only log if we have a real task that was previously created
603                 if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
604                 {
605                     System.Threading.Tasks.Task.RemoveFromActiveTasks(task.Id);
606                 }
607 
608                 if (!task.TrySetResult(result))
609                 {
610                     throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
611                 }
612             }
613         }
614 
615         /// <summary>
616         /// Completes the builder by using either the supplied completed task, or by completing
617         /// the builder's previously accessed task using default(TResult).
618         /// </summary>
619         /// <param name="completedTask">A task already completed with the value default(TResult).</param>
620         /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
621         internal void SetResult(Task<TResult> completedTask)
622         {
623             Contract.Requires(completedTask != null, "Expected non-null task");
624             Contract.Requires(completedTask.Status == TaskStatus.RanToCompletion, "Expected a successfully completed task");
625 
626             // Get the currently stored task, which will be non-null if get_Task has already been accessed.
627             // If there isn't one, store the supplied completed task.
628             var task = m_task;
629             if (task == null)
630             {
631                 m_task = completedTask;
632             }
633             else
634             {
635                 // Otherwise, complete the task that's there.
636                 SetResult(default(TResult));
637             }
638         }
639 
640         /// <summary>
641         /// Completes the <see cref="System.Threading.Tasks.Task{TResult}"/> in the
642         /// <see cref="System.Threading.Tasks.TaskStatus">Faulted</see> state with the specified exception.
643         /// </summary>
644         /// <param name="exception">The <see cref="System.Exception"/> to use to fault the task.</param>
645         /// <exception cref="System.ArgumentNullException">The <paramref name="exception"/> argument is null (Nothing in Visual Basic).</exception>
646         /// <exception cref="System.InvalidOperationException">The task has already completed.</exception>
647         public void SetException(Exception exception)
648         {
649             if (exception == null) throw new ArgumentNullException("exception");
650             Contract.EndContractBlock();
651 
652 
653             var task = m_task;
654             if (task == null)
655             {
656                 // Get the task, forcing initialization if it hasn't already been initialized.
657                 task = this.Task;
658             }
659 
660             // If the exception represents cancellation, cancel the task.  Otherwise, fault the task.
661             var oce = exception as OperationCanceledException;
662             bool successfullySet = oce != null ?
663                 task.TrySetCanceled(oce.CancellationToken, oce) :
664                 task.TrySetException(exception);
665 
666             // Unlike with TaskCompletionSource, we do not need to spin here until m_task is completed,
667             // since AsyncTaskMethodBuilder.SetException should not be immediately followed by any code
668             // that depends on the task having completely completed.  Moreover, with correct usage,
669             // SetResult or SetException should only be called once, so the Try* methods should always
670             // return true, so no spinning would be necessary anyway (the spinning in TCS is only relevant
671             // if another thread won the ---- to complete the task).
672 
673             if (!successfullySet)
674             {
675                 throw new InvalidOperationException(Environment.GetResourceString("TaskT_TransitionToFinal_AlreadyCompleted"));
676             }
677         }
678 
679         /// <summary>
680         /// Called by the debugger to request notification when the first wait operation
681         /// (await, Wait, Result, etc.) on this builder's task completes.
682         /// </summary>
683         /// <param name="enabled">
684         /// true to enable notification; false to disable a previously set notification.
685         /// </param>
686         /// <remarks>
687         /// This should only be invoked from within an asynchronous method,
688         /// and only by the debugger.
689         /// </remarks>
690         internal void SetNotificationForWaitCompletion(bool enabled)
691         {
692             // Get the task (forcing initialization if not already initialized), and set debug notification
693             this.Task.SetNotificationForWaitCompletion(enabled);
694         }
695 
696         /// <summary>
697         /// Gets an object that may be used to uniquely identify this builder to the debugger.
698         /// </summary>
699         /// <remarks>
700         /// This property lazily instantiates the ID in a non-thread-safe manner.
701         /// It must only be used by the debugger and tracing purposes, and only in a single-threaded manner
702         /// when no other threads are in the middle of accessing this property or this.Task.
703         /// </remarks>
704         private object ObjectIdForDebugger { get { return this.Task; } }
705 
706         /// <summary>
707         /// Gets a task for the specified result.  This will either
708         /// be a cached or new task, never null.
709         /// </summary>
710         /// <param name="result">The result for which we need a task.</param>
711         /// <returns>The completed task containing the result.</returns>
712         [SecuritySafeCritical] // for JitHelpers.UnsafeCast
713         private Task<TResult> GetTaskForResult(TResult result)
714         {
715             Contract.Ensures(
716                 EqualityComparer<TResult>.Default.Equals(result, Contract.Result<Task<TResult>>().Result),
717                 "The returned task's Result must return the same value as the specified result value.");
718 
719             // The goal of this function is to be give back a cached task if possible,
720             // or to otherwise give back a new task.  To give back a cached task,
721             // we need to be able to evaluate the incoming result value, and we need
722             // to avoid as much overhead as possible when doing so, as this function
723             // is invoked as part of the return path from every async method.
724             // Most tasks won't be cached, and thus we need the checks for those that are
725             // to be as close to free as possible. This requires some trickiness given the
726             // lack of generic specialization in .NET.
727             //
728             // Be very careful when modifying this code.  It has been tuned
729             // to comply with patterns recognized by both 32-bit and 64-bit JITs.
730             // If changes are made here, be sure to look at the generated assembly, as
731             // small tweaks can have big consequences for what does and doesn't get optimized away.
732             //
733             // Note that this code only ever accesses a static field when it knows it'll
734             // find a cached value, since static fields (even if readonly and integral types)
735             // require special access helpers in this NGEN'd and domain-neutral.
736 
737             if (null != (object)default(TResult)) // help the JIT avoid the value type branches for ref types
738             {
739                 // Special case simple value types:
740                 // - Boolean
741                 // - Byte, SByte
742                 // - Char
743                 // - Decimal
744                 // - Int32, UInt32
745                 // - Int64, UInt64
746                 // - Int16, UInt16
747                 // - IntPtr, UIntPtr
748                 // As of .NET 4.5, the (Type)(object)result pattern used below
749                 // is recognized and optimized by both 32-bit and 64-bit JITs.
750 
751                 // For Boolean, we cache all possible values.
752                 if (typeof(TResult) == typeof(Boolean)) // only the relevant branches are kept for each value-type generic instantiation
753                 {
754                     Boolean value = (Boolean)(object)result;
755                     Task<Boolean> task = value ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask;
756                     return JitHelpers.UnsafeCast<Task<TResult>>(task); // UnsafeCast avoids type check we know will succeed
757                 }
758                 // For Int32, we cache a range of common values, e.g. [-1,4).
759                 else if (typeof(TResult) == typeof(Int32))
760                 {
761                     // Compare to constants to avoid static field access if outside of cached range.
762                     // We compare to the upper bound first, as we're more likely to cache miss on the upper side than on the
763                     // lower side, due to positive values being more common than negative as return values.
764                     Int32 value = (Int32)(object)result;
765                     if (value < AsyncTaskCache.EXCLUSIVE_INT32_MAX &&
766                         value >= AsyncTaskCache.INCLUSIVE_INT32_MIN)
767                     {
768                         Task<Int32> task = AsyncTaskCache.Int32Tasks[value - AsyncTaskCache.INCLUSIVE_INT32_MIN];
769                         return JitHelpers.UnsafeCast<Task<TResult>>(task); // UnsafeCast avoids a type check we know will succeed
770                     }
771                 }
772                 // For other known value types, we only special-case 0 / default(TResult).
773                 else if (
774                     (typeof(TResult) == typeof(UInt32) && default(UInt32) == (UInt32)(object)result) ||
775                     (typeof(TResult) == typeof(Byte) && default(Byte) == (Byte)(object)result) ||
776                     (typeof(TResult) == typeof(SByte) && default(SByte) == (SByte)(object)result) ||
777                     (typeof(TResult) == typeof(Char) && default(Char) == (Char)(object)result) ||
778                     (typeof(TResult) == typeof(Decimal) && default(Decimal) == (Decimal)(object)result) ||
779                     (typeof(TResult) == typeof(Int64) && default(Int64) == (Int64)(object)result) ||
780                     (typeof(TResult) == typeof(UInt64) && default(UInt64) == (UInt64)(object)result) ||
781                     (typeof(TResult) == typeof(Int16) && default(Int16) == (Int16)(object)result) ||
782                     (typeof(TResult) == typeof(UInt16) && default(UInt16) == (UInt16)(object)result) ||
783                     (typeof(TResult) == typeof(IntPtr) && default(IntPtr) == (IntPtr)(object)result) ||
784                     (typeof(TResult) == typeof(UIntPtr) && default(UIntPtr) == (UIntPtr)(object)result))
785                 {
786                     return s_defaultResultTask;
787                 }
788             }
789             else if (result == null) // optimized away for value types
790             {
791                 return s_defaultResultTask;
792             }
793 
794             // No cached task is available.  Manufacture a new one for this result.
795             return new Task<TResult>(result);
796         }
797     }
798 
799     /// <summary>Provides a cache of closed generic tasks for async methods.</summary>
800     internal static class AsyncTaskCache
801     {
802         // All static members are initialized inline to ensure type is beforefieldinit
803 
804         /// <summary>A cached Task{Boolean}.Result == true.</summary>
805         internal readonly static Task<Boolean> TrueTask = CreateCacheableTask(true);
806         /// <summary>A cached Task{Boolean}.Result == false.</summary>
807         internal readonly static Task<Boolean> FalseTask = CreateCacheableTask(false);
808 
809         /// <summary>The cache of Task{Int32}.</summary>
810         internal readonly static Task<Int32>[] Int32Tasks = CreateInt32Tasks();
811         /// <summary>The minimum value, inclusive, for which we want a cached task.</summary>
812         internal const Int32 INCLUSIVE_INT32_MIN = -1;
813         /// <summary>The maximum value, exclusive, for which we want a cached task.</summary>
814         internal const Int32 EXCLUSIVE_INT32_MAX = 9;
815         /// <summary>Creates an array of cached tasks for the values in the range [INCLUSIVE_MIN,EXCLUSIVE_MAX).</summary>
816         private static Task<Int32>[] CreateInt32Tasks()
817         {
818             Contract.Assert(EXCLUSIVE_INT32_MAX >= INCLUSIVE_INT32_MIN, "Expected max to be at least min");
819             var tasks = new Task<Int32>[EXCLUSIVE_INT32_MAX - INCLUSIVE_INT32_MIN];
820             for (int i = 0; i < tasks.Length; i++)
821             {
822                 tasks[i] = CreateCacheableTask(i + INCLUSIVE_INT32_MIN);
823             }
824             return tasks;
825         }
826 
827         /// <summary>Creates a non-disposable task.</summary>
828         /// <typeparam name="TResult">Specifies the result type.</typeparam>
829         /// <param name="result">The result for the task.</param>
830         /// <returns>The cacheable task.</returns>
831         internal static Task<TResult> CreateCacheableTask<TResult>(TResult result)
832         {
833             return new Task<TResult>(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
834         }
835     }
836 
837     /// <summary>Holds state related to the builder's IAsyncStateMachine.</summary>
838     /// <remarks>This is a mutable struct.  Be very delicate with it.</remarks>
839     internal struct AsyncMethodBuilderCore
840     {
841         /// <summary>A reference to the heap-allocated state machine object associated with this builder.</summary>
842         internal IAsyncStateMachine m_stateMachine;
843         /// <summary>A cached Action delegate used when dealing with a default ExecutionContext.</summary>
844         internal Action m_defaultContextAction;
845 
846         // This method is copy&pasted into the public Start methods to avoid size overhead of valuetype generic instantiations.
847         // Ideally, we would build intrinsics to get the raw ref address and raw code address of MoveNext, and just use the shared implementation.
848 #if false
849         /// <summary>Initiates the builder's execution with the associated state machine.</summary>
850         /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
851         /// <param name="stateMachine">The state machine instance, passed by reference.</param>
852         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument is null (Nothing in Visual Basic).</exception>
853         [SecuritySafeCritical]
854         [DebuggerStepThrough]
855         internal static void Start<TStateMachine>(ref TStateMachine stateMachine)
856             where TStateMachine : IAsyncStateMachine
857         {
858             if (stateMachine == null) throw new ArgumentNullException("stateMachine");
859             Contract.EndContractBlock();
860 
861             // Run the MoveNext method within a copy-on-write ExecutionContext scope.
862             // This allows us to undo any ExecutionContext changes made in MoveNext,
863             // so that they won't "leak" out of the first await.
864 
865             Thread currentThread = Thread.CurrentThread;
866             ExecutionContextSwitcher ecs = default(ExecutionContextSwitcher);
867             RuntimeHelpers.PrepareConstrainedRegions();
868             try
869             {
870                 ExecutionContext.EstablishCopyOnWriteScope(ref ecs);
871                 stateMachine.MoveNext();
872             }
873             finally
874             {
875                 ecs.Undo();
876             }
877         }
878 #endif
879 
880         /// <summary>Associates the builder with the state machine it represents.</summary>
881         /// <param name="stateMachine">The heap-allocated state machine object.</param>
882         /// <exception cref="System.ArgumentNullException">The <paramref name="stateMachine"/> argument was null (Nothing in Visual Basic).</exception>
883         /// <exception cref="System.InvalidOperationException">The builder is incorrectly initialized.</exception>
884         public void SetStateMachine(IAsyncStateMachine stateMachine)
885         {
886             if (stateMachine == null) throw new ArgumentNullException("stateMachine");
887             Contract.EndContractBlock();
888             if (m_stateMachine != null) throw new InvalidOperationException(Environment.GetResourceString("AsyncMethodBuilder_InstanceNotInitialized"));
889             m_stateMachine = stateMachine;
890         }
891 
892         /// <summary>
893         /// Gets the Action to use with an awaiter's OnCompleted or UnsafeOnCompleted method.
894         /// On first invocation, the supplied state machine will be boxed.
895         /// </summary>
896         /// <typeparam name="TMethodBuilder">Specifies the type of the method builder used.</typeparam>
897         /// <typeparam name="TStateMachine">Specifies the type of the state machine used.</typeparam>
898         /// <param name="builder">The builder.</param>
899         /// <param name="stateMachine">The state machine.</param>
900         /// <returns>An Action to provide to the awaiter.</returns>
901         [SecuritySafeCritical]
902         internal Action GetCompletionAction(Task taskForTracing, ref MoveNextRunner runnerToInitialize)
903         {
904             Contract.Assert(m_defaultContextAction == null || m_stateMachine != null,
905                 "Expected non-null m_stateMachine on non-null m_defaultContextAction");
906 
907             // Alert a listening debugger that we can't make forward progress unless it slips threads.
908             // If we don't do this, and a method that uses "await foo;" is invoked through funceval,
909             // we could end up hooking up a callback to push forward the async method's state machine,
910             // the debugger would then abort the funceval after it takes too long, and then continuing
911             // execution could result in another callback being hooked up.  At that point we have
912             // multiple callbacks registered to push the state machine, which could result in bad behavior.
913             Debugger.NotifyOfCrossThreadDependency();
914 
915             // The builder needs to flow ExecutionContext, so capture it.
916             var capturedContext = ExecutionContext.FastCapture(); // ok to use FastCapture as we haven't made any permission demands/asserts
917 
918             // If the ExecutionContext is the default context, try to use a cached delegate, creating one if necessary.
919             Action action;
920             MoveNextRunner runner;
921             if (capturedContext != null && capturedContext.IsPreAllocatedDefault)
922             {
923                 // Get the cached delegate, and if it's non-null, return it.
924                 action = m_defaultContextAction;
925                 if (action != null)
926                 {
927                     Contract.Assert(m_stateMachine != null, "If the delegate was set, the state machine should have been as well.");
928                     return action;
929                 }
930 
931                 // There wasn't a cached delegate, so create one and cache it.
932                 // The delegate won't be usable until we set the MoveNextRunner's target state machine.
933                 runner = new MoveNextRunner(capturedContext, m_stateMachine);
934 
935                 action = new Action(runner.Run);
936                 if (taskForTracing != null)
937                 {
938                     m_defaultContextAction = action = OutputAsyncCausalityEvents(taskForTracing, action);
939                 }
940                 else
941                 {
942                     m_defaultContextAction = action;
943                 }
944             }
945             // Otherwise, create an Action that flows this context.  The context may be null.
946             // The delegate won't be usable until we set the MoveNextRunner's target state machine.
947             else
948             {
949                 runner = new MoveNextRunner(capturedContext, m_stateMachine);
950                 action = new Action(runner.Run);
951 
952                 if (taskForTracing != null)
953                 {
954                     action = OutputAsyncCausalityEvents(taskForTracing, action);
955                 }
956 
957                 // NOTE: If capturedContext is null, we could create the Action to point directly
958                 // to m_stateMachine.MoveNext.  However, that follows a much more expensive
959                 // delegate creation path.
960             }
961 
962             if (m_stateMachine == null)
963                 runnerToInitialize = runner;
964 
965             return action;
966         }
967 
968         private Action OutputAsyncCausalityEvents(Task innerTask, Action continuation)
969         {
970             return CreateContinuationWrapper(continuation, () =>
971             {
972                 AsyncCausalityTracer.TraceSynchronousWorkStart(CausalityTraceLevel.Required, innerTask.Id, CausalitySynchronousWork.Execution);
973 
974                 // Invoke the original continuation
975                 continuation.Invoke();
976 
977                 AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalityTraceLevel.Required, CausalitySynchronousWork.Execution);
978             }, innerTask);
979         }
980 
981         internal void PostBoxInitialization(IAsyncStateMachine stateMachine, MoveNextRunner runner, Task builtTask)
982         {
983             if (builtTask != null)
984             {
985                 if (AsyncCausalityTracer.LoggingOn)
986                     AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, builtTask.Id, "Async: " + stateMachine.GetType().Name, 0);
987 
988                 if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
989                     System.Threading.Tasks.Task.AddToActiveTasks(builtTask);
990             }
991 
992             m_stateMachine = stateMachine;
993             m_stateMachine.SetStateMachine(m_stateMachine);
994 
995             Contract.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated.");
996             Contract.Assert(m_stateMachine != null, "The builder's state machine field should have been initialized.");
997 
998             // Now that we have the state machine, store it into the runner that the action delegate points to.
999             // And return the action.
1000             runner.m_stateMachine = m_stateMachine; // only after this line is the Action delegate usable
1001         }
1002 
1003         /// <summary>Throws the exception on the ThreadPool.</summary>
1004         /// <param name="exception">The exception to propagate.</param>
1005         /// <param name="targetContext">The target context on which to propagate the exception.  Null to use the ThreadPool.</param>
1006         internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext)
1007         {
1008             // Capture the exception into an ExceptionDispatchInfo so that its
1009             // stack trace and Watson bucket info will be preserved
1010             var edi = ExceptionDispatchInfo.Capture(exception);
1011 
1012             // If the user supplied a SynchronizationContext...
1013             if (targetContext != null)
1014             {
1015                 try
1016                 {
1017                     // Post the throwing of the exception to that context, and return.
1018                     targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi);
1019                     return;
1020                 }
1021                 catch (Exception postException)
1022                 {
1023                     // If something goes horribly wrong in the Post, we'll
1024                     // propagate both exceptions on the ThreadPool
1025                     edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException));
1026                 }
1027             }
1028 
1029             // If we have the new error reporting APIs, report this error.  Otherwise, Propagate the exception(s) on the ThreadPool
1030 #if FEATURE_COMINTEROP
1031             if (!WindowsRuntimeMarshal.ReportUnhandledError(edi.SourceException))
1032 #endif // FEATURE_COMINTEROP
1033             {
1034                 ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state).Throw(), edi);
1035             }
1036         }
1037 
1038         /// <summary>Provides the ability to invoke a state machine's MoveNext method under a supplied ExecutionContext.</summary>
1039         internal sealed class MoveNextRunner
1040         {
1041             /// <summary>The context with which to run MoveNext.</summary>
1042             private readonly ExecutionContext m_context;
1043             /// <summary>The state machine whose MoveNext method should be invoked.</summary>
1044             internal IAsyncStateMachine m_stateMachine;
1045 
1046             /// <summary>Initializes the runner.</summary>
1047             /// <param name="context">The context with which to run MoveNext.</param>
1048             [SecurityCritical] // Run needs to be SSC to map to Action delegate, so to prevent misuse, we only allow construction through SC
1049             internal MoveNextRunner(ExecutionContext context, IAsyncStateMachine stateMachine)
1050             {
1051                 m_context = context;
1052                 m_stateMachine = stateMachine;
1053             }
1054 
1055             /// <summary>Invokes MoveNext under the provided context.</summary>
1056             [SecuritySafeCritical]
1057             internal void Run()
1058             {
1059                 Contract.Assert(m_stateMachine != null, "The state machine must have been set before calling Run.");
1060 
1061                 if (m_context != null)
1062                 {
1063                     try
1064                     {
1065                         // Get the callback, lazily initializing it as necessary
1066                         ContextCallback callback = s_invokeMoveNext;
1067                         if (callback == null) { s_invokeMoveNext = callback = InvokeMoveNext; }
1068 
1069                         // Use the context and callback to invoke m_stateMachine.MoveNext.
1070                         ExecutionContext.Run(m_context, callback, m_stateMachine, preserveSyncCtx: true);
1071                     }
1072                     finally { m_context.Dispose(); }
1073                 }
1074                 else
1075                 {
1076                     m_stateMachine.MoveNext();
1077                 }
1078             }
1079 
1080             /// <summary>Cached delegate used with ExecutionContext.Run.</summary>
1081             [SecurityCritical]
1082             private static ContextCallback s_invokeMoveNext; // lazily-initialized due to SecurityCritical attribution
1083 
1084             /// <summary>Invokes the MoveNext method on the supplied IAsyncStateMachine.</summary>
1085             /// <param name="stateMachine">The IAsyncStateMachine machine instance.</param>
1086             [SecurityCritical] // necessary for ContextCallback in CoreCLR
1087             private static void InvokeMoveNext(object stateMachine)
1088             {
1089                 ((IAsyncStateMachine)stateMachine).MoveNext();
1090             }
1091         }
1092 
1093         /// <summary>
1094         /// Logically we pass just an Action (delegate) to a task for its action to 'ContinueWith' when it completes.
1095         /// However debuggers and profilers need more information about what that action is. (In particular what
1096         /// the action after that is and after that.   To solve this problem we create a 'ContinuationWrapper
1097         /// which when invoked just does the original action (the invoke action), but also remembers other information
1098         /// (like the action after that (which is also a ContinuationWrapper and thus form a linked list).
1099         //  We also store that task if the action is associate with at task.
1100         /// </summary>
1101         private class ContinuationWrapper
1102         {
1103             internal readonly Action m_continuation;        // This is continuation which will happen after m_invokeAction  (and is probably a ContinuationWrapper)
1104             private readonly Action m_invokeAction;         // This wrapper is an action that wraps another action, this is that Action.
1105             internal readonly Task m_innerTask;             // If the continuation is logically going to invoke a task, this is that task (may be null)
1106 
1107             internal ContinuationWrapper(Action continuation, Action invokeAction, Task innerTask)
1108             {
1109                 Contract.Requires(continuation != null, "Expected non-null continuation");
1110 
1111                 // If we don't have a task, see if our continuation is a wrapper and use that.
1112                 if (innerTask == null)
1113                     innerTask = TryGetContinuationTask(continuation);
1114 
1115                 m_continuation = continuation;
1116                 m_innerTask = innerTask;
1117                 m_invokeAction = invokeAction;
1118             }
1119 
1120             internal void Invoke()
1121             {
1122                 m_invokeAction();
1123             }
1124         }
1125 
1126         internal static Action CreateContinuationWrapper(Action continuation, Action invokeAction, Task innerTask = null)
1127         {
1128             return new ContinuationWrapper(continuation, invokeAction, innerTask).Invoke;
1129         }
1130 
1131         internal static Action TryGetStateMachineForDebugger(Action action)
1132         {
1133             object target = action.Target;
1134             var runner = target as AsyncMethodBuilderCore.MoveNextRunner;
1135             if (runner != null)
1136             {
1137                 return new Action(runner.m_stateMachine.MoveNext);
1138             }
1139 
1140             var continuationWrapper = target as ContinuationWrapper;
1141             if (continuationWrapper != null)
1142             {
1143                 return TryGetStateMachineForDebugger(continuationWrapper.m_continuation);
1144             }
1145 
1146             return action;
1147         }
1148 
1149     ///<summary>
1150     /// Given an action, see if it is a contiunation wrapper and has a Task associated with it.  If so return it (null otherwise)
1151     ///</summary>
1152         internal static Task TryGetContinuationTask(Action action)
1153         {
1154             if (action != null)
1155             {
1156                 var asWrapper = action.Target as ContinuationWrapper;
1157                 if (asWrapper != null)
1158                     return asWrapper.m_innerTask;
1159             }
1160             return null;
1161         }
1162     }
1163 }
1164