// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; using System.Threading; namespace System.Runtime.CompilerServices { internal static partial class AsyncMethodBuilder { /// Initiates the builder's execution with the associated state machine. /// Specifies the type of the state machine. /// The state machine instance, passed by reference. [DebuggerStepThrough] public static void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { if (stateMachine == null) // TStateMachines are generally non-nullable value types, so this check will be elided { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.stateMachine); } // enregistrer variables with 0 post-fix so they can be used in registers without EH forcing them to stack // Capture references to Thread Contexts Thread currentThread0 = Thread.CurrentThread; Thread currentThread = currentThread0; ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext; // Store current ExecutionContext and SynchronizationContext as "previousXxx". // This allows us to restore them and undo any Context changes made in stateMachine.MoveNext // so that they won't "leak" out of the first await. ExecutionContext previousExecutionCtx = previousExecutionCtx0; SynchronizationContext previousSyncCtx = currentThread0.SynchronizationContext; try { stateMachine.MoveNext(); } finally { // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack SynchronizationContext previousSyncCtx1 = previousSyncCtx; Thread currentThread1 = currentThread; // The common case is that these have not changed, so avoid the cost of a write barrier if not needed. if (previousSyncCtx1 != currentThread1.SynchronizationContext) { // Restore changed SynchronizationContext back to previous currentThread1.SynchronizationContext = previousSyncCtx1; } ExecutionContext previousExecutionCtx1 = previousExecutionCtx; ExecutionContext currentExecutionCtx1 = currentThread1.ExecutionContext; if (previousExecutionCtx1 != currentExecutionCtx1) { // Restore changed ExecutionContext back to previous currentThread1.ExecutionContext = previousExecutionCtx1; if ((currentExecutionCtx1 != null && currentExecutionCtx1.HasChangeNotifications) || (previousExecutionCtx1 != null && previousExecutionCtx1.HasChangeNotifications)) { // There are change notifications; trigger any affected ExecutionContext.OnValuesChanged(currentExecutionCtx1, previousExecutionCtx1); } } } } } }