1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 using System.Diagnostics;
7 using System.Threading;
9 namespace System.Runtime.CompilerServices
11 internal static partial class AsyncMethodBuilder
13 /// <summary>Initiates the builder's execution with the associated state machine.</summary>
14 /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
15 /// <param name="stateMachine">The state machine instance, passed by reference.</param>
17 public static void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
19 if (stateMachine == null) // TStateMachines are generally non-nullable value types, so this check will be elided
21 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine);
24 // enregistrer variables with 0 post-fix so they can be used in registers without EH forcing them to stack
25 // Capture references to Thread Contexts
26 Thread currentThread0 = Thread.CurrentThread;
27 Thread currentThread = currentThread0;
28 ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext;
30 // Store current ExecutionContext and SynchronizationContext as "previousXxx".
31 // This allows us to restore them and undo any Context changes made in stateMachine.MoveNext
32 // so that they won't "leak" out of the first await.
33 ExecutionContext previousExecutionCtx = previousExecutionCtx0;
34 SynchronizationContext previousSyncCtx = currentThread0.SynchronizationContext;
38 stateMachine.MoveNext();
42 // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack
43 SynchronizationContext previousSyncCtx1 = previousSyncCtx;
44 Thread currentThread1 = currentThread;
45 // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
46 if (previousSyncCtx1 != currentThread1.SynchronizationContext)
48 // Restore changed SynchronizationContext back to previous
49 currentThread1.SynchronizationContext = previousSyncCtx1;
52 ExecutionContext previousExecutionCtx1 = previousExecutionCtx;
53 ExecutionContext currentExecutionCtx1 = currentThread1.ExecutionContext;
54 if (previousExecutionCtx1 != currentExecutionCtx1)
56 // Restore changed ExecutionContext back to previous
57 currentThread1.ExecutionContext = previousExecutionCtx1;
58 if ((currentExecutionCtx1 != null && currentExecutionCtx1.HasChangeNotifications) ||
59 (previousExecutionCtx1 != null && previousExecutionCtx1.HasChangeNotifications))
61 // There are change notifications; trigger any affected
62 ExecutionContext.OnValuesChanged(currentExecutionCtx1, previousExecutionCtx1);