public void AwaitUnsafeOnCompleted <TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { try { if (_stateMachine == null) { var ignored = Task; // NB: Ensure we have the observable backed by an async subject ready. _stateMachine = stateMachine; _stateMachine.SetStateMachine(_stateMachine); } // NB: Rx has historically not bothered with execution contexts, so we don't do it here either. awaiter.UnsafeOnCompleted(_stateMachine.MoveNext); } catch (Exception ex) { // NB: Prevent reentrancy into the async state machine when an exception would be observed // by the caller. This could cause concurrent execution of the async method. Instead, // rethrow the exception elsewhere. Rethrow(ex); } }
/// <summary> /// Gets the Action to use with an awaiter's OnCompleted or 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 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 { // 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 (m_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. m_stateMachine = (IAsyncStateMachine)stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); } // Now that we have the state machine, store it into the runner that the action delegate points to. // And return the action. runner.m_stateMachine = m_stateMachine; // only after this line is the Action delegate usable return(action); }
private void SetTCS(IAsyncStateMachine machine, TaskCompletionSource <T> tcs) { // Option 1: (works only in release mode) // TODO: measure if it is any faster tcsGlobalSignal = tcs; machine.SetStateMachine(machine); if (tcsGlobalSignal is object) { IOTaskMethodBuilder <T> newBuilder; newBuilder.preboxedMachine = machine; newBuilder.tcs = tcs; newBuilder.boxedMoveNext = null; newBuilder.resultIO = this; // TODO: add preboxed machine tcsGlobalSignal = null; machine.GetType().GetField("<>t__builder").SetValue(machine, newBuilder); // // Using DLR // // https://sharplab.io/#v2:D4AQTAjAsAULBuBDATgAgCaoLyoHYFMB3DAFgAoBKAblgGEA6AWTPQBoN8AzRAVwBsALtVjp6ASVwBnAA74AxgMo04MSfkR98mcKVgBvWAEgQAZlQBLXANSSBiAfmWxUL1KdSMAngGUByHgqoAgBGPOZ86PjIyq6osAC+sLC2/oFevqnWBjCx7pbWAB7KiSo6tKjZsW5mIBAAbG4kHmQA8sEAVvLWiOzpfgGFFBXOVbFkLJ64iAC25nIUiBT0IWERUdioRSOuJfFAA== // if (callSiteCache is null) // { // Type context = typeof(BuiltIO); // var args = new CSharpArgumentInfo[] { // CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), // CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) // }; // callSiteCache = CallSite<Func<CallSite, object, IOTaskMethodBuilder<T>, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.SetMember(CSharpBinderFlags.None, "<>t__builder", context, args)); // } // callSiteCache.Target(callSiteCache, machine, newBuilder); } }
Action GetCompletionAction <TStateMachine> (ref TStateMachine machine) where TStateMachine : IAsyncStateMachine { // If this is our first await, such that we've not yet boxed the state machine, do so now. if (stateMachine == null) { stateMachine = (IAsyncStateMachine)machine; stateMachine.SetStateMachine(stateMachine); } var runner = new Runner(stateMachine, scope); return(new Action(runner.Run)); }
internal Action GetCompletionAction <TMethodBuilder, TStateMachine>(TMethodBuilder builder, TStateMachine stateMachine) where TMethodBuilder : IAsyncMethodBuilder where TStateMachine : IAsyncStateMachine { if (m_stateMachine == null) { m_stateMachine = stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); } Action action = 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 (m_stateMachine == null) { builder.PreBoxInitialization(); m_stateMachine = stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); } moveNextRunner.m_stateMachine = m_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); }
internal void PostBoxInitialization <TResult>(IAsyncStateMachine stateMachine, MoveNextRunner runner, Task builtTask, TaskCompletionSource <TResult> tcs) { if (builtTask != null) { } m_stateMachine = stateMachine; m_stateMachine.SetStateMachine(m_stateMachine); ((IBuilderStateMachine <TResult>)m_stateMachine).SetBuilderTcs(tcs); Contract.Assert(runner.m_stateMachine == null, "The runner's state machine should not yet have been populated."); Contract.Assert(m_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. runner.m_stateMachine = m_stateMachine; // only after this line is the Action delegate usable }
/// <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; }