public void AwaitOnCompleted <TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { Console.WriteLine("In AwaitOnCompleted"); var executionContext = ExecutionContext.Capture(); var moveNextRunner = new MoveNextRunner(stateMachine, executionContext); awaiter.OnCompleted(moveNextRunner.MoveNextSafe); }
public void AwaitUnsafeOnCompleted <TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { Console.WriteLine("In AwaitUnsafeOnCompleted"); var moveNextRunner = new MoveNextRunner(stateMachine); awaiter.UnsafeOnCompleted(moveNextRunner.MoveNextUnsafe); }
internal static Action TryGetStateMachineForDebugger(Action action) { Object target = action.Target; MoveNextRunner runner = target as MoveNextRunner; if (runner != null) { return(runner.m_stateMachine.MoveNext); } return(action); }
internal Action GetCompletionAction <TMethodBuilder, TStateMachine>(ref TMethodBuilder builder, ref TStateMachine stateMachine) where TMethodBuilder : IAsyncMethodBuilder where TStateMachine : IAsyncStateMachine { var context = ExecutionContextLightup.Instance.Capture(); var moveNextRunner = new MoveNextRunner(context); var result = new Action(moveNextRunner.Run); if (m_stateMachine == null) { builder.PreBoxInitialization(); m_stateMachine = stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); } moveNextRunner.m_stateMachine = m_stateMachine; return(result); }
internal Action GetCompletionAction <TMethodBuilder, TStateMachine>(ref TMethodBuilder builder, ref TStateMachine stateMachine) where TMethodBuilder : IAsyncMethodBuilder where TStateMachine : IAsyncStateMachine { var moveNextRunner = new MoveNextRunner(ExecutionContext.Capture()); Action action = moveNextRunner.Run; if (this.stateMachine == null) { builder.PreBoxInitialization(); this.stateMachine = stateMachine; this.stateMachine.SetStateMachine(this.stateMachine); } moveNextRunner.StateMachine = this.stateMachine; return(action); }
/// <summary> /// Gets the <see cref="Action"/> to use with an awaiter's <see cref="INotifyCompletion.OnCompleted"/> or /// <see cref="ICriticalNotifyCompletion.UnsafeOnCompleted"/> method. On first invocation, the supplied state /// machine will be boxed. /// </summary> /// <typeparam name="TMethodBuilder">Specifies the type of the method builder used.</typeparam> /// <typeparam name="TStateMachine">Specifies the type of the state machine used.</typeparam> /// <param name="builder">The builder.</param> /// <param name="stateMachine">The state machine.</param> /// <returns>An <see cref="Action"/> to provide to the awaiter.</returns> internal Action GetCompletionAction <TMethodBuilder, TStateMachine>(ref TMethodBuilder builder, ref TStateMachine stateMachine) where TMethodBuilder : IAsyncMethodBuilder where TStateMachine : IAsyncStateMachine { ExecutionContext context = ExecutionContext.Capture(); MoveNextRunner moveNextRunner = new MoveNextRunner(context); Action result = moveNextRunner.Run; if (_stateMachine == null) { builder.PreBoxInitialization(ref stateMachine); _stateMachine = stateMachine; _stateMachine.SetStateMachine(_stateMachine); } moveNextRunner._stateMachine = _stateMachine; return(result); }
/// <summary> /// Gets the <see cref="Action"/> to use with an awaiter's <see cref="INotifyCompletion.OnCompleted"/> or /// <see cref="ICriticalNotifyCompletion.UnsafeOnCompleted"/> method. On first invocation, the supplied state /// machine will be boxed. /// </summary> /// <typeparam name="TMethodBuilder">Specifies the type of the method builder used.</typeparam> /// <typeparam name="TStateMachine">Specifies the type of the state machine used.</typeparam> /// <param name="builder">The builder.</param> /// <param name="stateMachine">The state machine.</param> /// <returns>An <see cref="Action"/> to provide to the awaiter.</returns> #if !SILVERLIGHT //// [SecuritySafeCritical] #endif internal Action GetCompletionAction<TMethodBuilder, TStateMachine>(ref TMethodBuilder builder, ref TStateMachine stateMachine) where TMethodBuilder : IAsyncMethodBuilder where TStateMachine : IAsyncStateMachine { Debug.Assert(builder != null, "Expected valid builder"); Debug.Assert(stateMachine != null, "Expected valid state machine reference"); // The builder needs to flow ExecutionContext, so capture it. var capturedContext = ExecutionContextLightup.Instance.Capture(); MoveNextRunner runner = new MoveNextRunner(capturedContext); Action action = new Action(runner.Run); // If this is our first await, such that we've not yet boxed the state machine, do so now. if (_stateMachine == null) { // This is our first await, and we're not boxed yet. First performance any work that must affect both // the non-boxed and boxed builders. builder.PreBoxInitialization(); // Box the state machine, then tell the boxed instance to call back into its own builder, so we can // cache the boxed reference. Debug.Assert(!object.ReferenceEquals((object)stateMachine, (object)stateMachine), "Expected an unboxed state machine reference"); _stateMachine = stateMachine; _stateMachine.SetStateMachine(_stateMachine); } Debug.Assert(runner._stateMachine == null, "The runner's state machine should not yet have been populated."); Debug.Assert(_stateMachine != null, "The builder's state machine field should have been initialized."); // Now that we have the state machine, store it into the runner that the action delegate points to. And // return the action. // // Only after this line is the Action delegate usable. runner._stateMachine = _stateMachine; return action; }
private static unsafe Action GetCompletionActionHelper( ref Action cachedMoveNextAction, ref byte stateMachineAddress, EETypePtr stateMachineType, Task taskIfDebuggingEnabled) { // Alert a listening debugger that we can't make forward progress unless it slips threads. // If we don't do this, and a method that uses "await foo;" is invoked through funceval, // we could end up hooking up a callback to push forward the async method's state machine, // the debugger would then abort the funceval after it takes too long, and then continuing // execution could result in another callback being hooked up. At that point we have // multiple callbacks registered to push the state machine, which could result in bad behavior. //Debugger.NotifyOfCrossThreadDependency(); MoveNextRunner runner; if (cachedMoveNextAction != null) { Debug.Assert(cachedMoveNextAction.Target is MoveNextRunner); runner = (MoveNextRunner)cachedMoveNextAction.Target; runner.m_executionContext = ExecutionContext.Capture(); return(cachedMoveNextAction); } runner = new MoveNextRunner(); runner.m_executionContext = ExecutionContext.Capture(); cachedMoveNextAction = runner.CallMoveNext; if (taskIfDebuggingEnabled != null) { runner.m_task = taskIfDebuggingEnabled; if (DebuggerSupport.LoggingOn) { IntPtr eeType = stateMachineType.RawValue; DebuggerSupport.TraceOperationCreation(CausalityTraceLevel.Required, taskIfDebuggingEnabled, "Async: " + eeType.ToString("x"), 0); } DebuggerSupport.AddToActiveTasks(taskIfDebuggingEnabled); } // // If the state machine is a value type, we need to box it now. // IAsyncStateMachine boxedStateMachine; if (stateMachineType.IsValueType) { object boxed = RuntimeImports.RhBox(stateMachineType, ref stateMachineAddress); Debug.Assert(boxed is IAsyncStateMachine); boxedStateMachine = Unsafe.As <IAsyncStateMachine>(boxed); } else { boxedStateMachine = Unsafe.As <byte, IAsyncStateMachine>(ref stateMachineAddress); } runner.m_stateMachine = boxedStateMachine; #if DEBUG // // In debug builds, we'll go ahead and call SetStateMachine, even though all of our initialization is done. // This way we'll keep forcing state machine implementations to keep the behavior needed by the CLR. // boxedStateMachine.SetStateMachine(boxedStateMachine); #endif // All done! return(cachedMoveNextAction); }