Last active
September 19, 2023 12:38
-
-
Save wi7a1ian/42ad24624850e9fa8842434ad329a0e6 to your computer and use it in GitHub Desktop.
Async/await internals in C# #csharp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
MainAsync().Wait(); | |
} | |
static async Task MainAsync() | |
{ | |
CancellationTokenSource cts = new CancellationTokenSource(); | |
var a = new SomeABClass(); | |
var l = await a.AAA(cts.Token); | |
} | |
public class SomeABClass | |
{ | |
public async Task<long> AAA(CancellationToken token) | |
{ | |
Stopwatch tick = new Stopwatch(); | |
tick.Start(); | |
await BBB(token); | |
await CCC(token); | |
tick.Stop(); | |
return tick.ElapsedMilliseconds; | |
} | |
private async Task BBB(CancellationToken token) | |
{ | |
await Task.Delay(TimeSpan.FromSeconds(1), token); | |
} | |
private async Task CCC(CancellationToken token) | |
{ | |
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
internal class Program | |
{ | |
private static void Main(string[] args) | |
{ | |
MainAsync().Wait(); | |
} | |
[AsyncStateMachine(typeof(<MainAsync>d__1))] | |
[DebuggerStepThrough] | |
private static Task MainAsync() | |
{ | |
<MainAsync>d__1 stateMachine = new <MainAsync>d__1(); | |
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); | |
stateMachine.<>1__state = -1; | |
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder; | |
<>t__builder.Start(ref stateMachine); | |
return stateMachine.<>t__builder.Task; | |
} | |
public class SomeABClass | |
{ | |
[AsyncStateMachine(typeof(<AAA>d__0))] | |
[DebuggerStepThrough] | |
public Task<long> AAA(CancellationToken token) | |
{ | |
<AAA>d__0 stateMachine = new <AAA>d__0(); | |
stateMachine.<>4__this = this; | |
stateMachine.token = token; | |
stateMachine.<>t__builder = AsyncTaskMethodBuilder<long>.Create(); | |
stateMachine.<>1__state = -1; | |
AsyncTaskMethodBuilder<long> <>t__builder = stateMachine.<>t__builder; | |
<>t__builder.Start(ref stateMachine); | |
return stateMachine.<>t__builder.Task; | |
} | |
[AsyncStateMachine(typeof(<BBB>d__1))] | |
[DebuggerStepThrough] | |
private Task BBB(CancellationToken token) | |
{ | |
<BBB>d__1 stateMachine = new <BBB>d__1(); | |
stateMachine.<>4__this = this; | |
stateMachine.token = token; | |
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); | |
stateMachine.<>1__state = -1; | |
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder; | |
<>t__builder.Start(ref stateMachine); | |
return stateMachine.<>t__builder.Task; | |
} | |
[AsyncStateMachine(typeof(<CCC>d__2))] | |
[DebuggerStepThrough] | |
private Task CCC(CancellationToken token) | |
{ | |
<CCC>d__2 stateMachine = new <CCC>d__2(); | |
stateMachine.<>4__this = this; | |
stateMachine.token = token; | |
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); | |
stateMachine.<>1__state = -1; | |
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder; | |
<>t__builder.Start(ref stateMachine); | |
return stateMachine.<>t__builder.Task; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CompilerGenerated] | |
private sealed class <AAA>d__0 : IAsyncStateMachine | |
{ | |
public int <>1__state; | |
public AsyncTaskMethodBuilder<long> <>t__builder; | |
public CancellationToken token; | |
public SomeABClass <>4__this; | |
private Stopwatch <tick>5__1; | |
private TaskAwaiter <>u__1; | |
private void MoveNext() | |
{ | |
int num = <>1__state; | |
long elapsedMilliseconds; | |
try | |
{ | |
TaskAwaiter awaiter; | |
TaskAwaiter awaiter2; | |
if (num != 0) | |
{ | |
if (num == 1) | |
{ | |
awaiter = <>u__1; | |
<>u__1 = default(TaskAwaiter); | |
num = (<>1__state = -1); | |
goto IL_00ff; | |
} | |
<tick>5__1 = new Stopwatch(); | |
<tick>5__1.Start(); | |
awaiter2 = <>4__this.BBB(token).GetAwaiter(); | |
if (!awaiter2.IsCompleted) | |
{ | |
num = (<>1__state = 0); | |
<>u__1 = awaiter2; | |
<AAA>d__0 stateMachine = this; | |
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine); | |
return; | |
} | |
} | |
else | |
{ | |
awaiter2 = <>u__1; | |
<>u__1 = default(TaskAwaiter); | |
num = (<>1__state = -1); | |
} | |
awaiter2.GetResult(); | |
awaiter = <>4__this.CCC(token).GetAwaiter(); | |
if (!awaiter.IsCompleted) | |
{ | |
num = (<>1__state = 1); | |
<>u__1 = awaiter; | |
<AAA>d__0 stateMachine = this; | |
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | |
return; | |
} | |
goto IL_00ff; | |
IL_00ff: | |
awaiter.GetResult(); | |
<tick>5__1.Stop(); | |
elapsedMilliseconds = <tick>5__1.ElapsedMilliseconds; | |
} | |
catch (Exception exception) | |
{ | |
<>1__state = -2; | |
<>t__builder.SetException(exception); | |
return; | |
} | |
<>1__state = -2; | |
<>t__builder.SetResult(elapsedMilliseconds); | |
} | |
void IAsyncStateMachine.MoveNext() | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in MoveNext | |
this.MoveNext(); | |
} | |
[DebuggerHidden] | |
private void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
} | |
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine | |
this.SetStateMachine(stateMachine); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CompilerGenerated] | |
private sealed class <BBB>d__1 : IAsyncStateMachine | |
{ | |
public int <>1__state; | |
public AsyncTaskMethodBuilder <>t__builder; | |
public CancellationToken token; | |
public SomeABClass <>4__this; | |
private TaskAwaiter <>u__1; | |
private void MoveNext() | |
{ | |
int num = <>1__state; | |
try | |
{ | |
TaskAwaiter awaiter; | |
if (num != 0) | |
{ | |
awaiter = Task.Delay(TimeSpan.FromSeconds(1.0), token).GetAwaiter(); | |
if (!awaiter.IsCompleted) | |
{ | |
num = (<>1__state = 0); | |
<>u__1 = awaiter; | |
<BBB>d__1 stateMachine = this; | |
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | |
return; | |
} | |
} | |
else | |
{ | |
awaiter = <>u__1; | |
<>u__1 = default(TaskAwaiter); | |
num = (<>1__state = -1); | |
} | |
awaiter.GetResult(); | |
} | |
catch (Exception exception) | |
{ | |
<>1__state = -2; | |
<>t__builder.SetException(exception); | |
return; | |
} | |
<>1__state = -2; | |
<>t__builder.SetResult(); | |
} | |
void IAsyncStateMachine.MoveNext() | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in MoveNext | |
this.MoveNext(); | |
} | |
[DebuggerHidden] | |
private void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
} | |
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine | |
this.SetStateMachine(stateMachine); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CompilerGenerated] | |
private sealed class <CCC>d__2 : IAsyncStateMachine | |
{ | |
public int <>1__state; | |
public AsyncTaskMethodBuilder <>t__builder; | |
public CancellationToken token; | |
public SomeABClass <>4__this; | |
private ConfiguredTaskAwaitable.ConfiguredTaskAwaiter <>u__1; | |
private void MoveNext() | |
{ | |
int num = <>1__state; | |
try | |
{ | |
ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter; | |
if (num != 0) | |
{ | |
awaiter = Task.Delay(TimeSpan.FromSeconds(1.0), token).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter(); | |
if (!awaiter.IsCompleted) | |
{ | |
num = (<>1__state = 0); | |
<>u__1 = awaiter; | |
<CCC>d__2 stateMachine = this; | |
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | |
return; | |
} | |
} | |
else | |
{ | |
awaiter = <>u__1; | |
<>u__1 = default(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter); | |
num = (<>1__state = -1); | |
} | |
awaiter.GetResult(); | |
} | |
catch (Exception exception) | |
{ | |
<>1__state = -2; | |
<>t__builder.SetException(exception); | |
return; | |
} | |
<>1__state = -2; | |
<>t__builder.SetResult(); | |
} | |
void IAsyncStateMachine.MoveNext() | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in MoveNext | |
this.MoveNext(); | |
} | |
[DebuggerHidden] | |
private void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
} | |
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine | |
this.SetStateMachine(stateMachine); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[CompilerGenerated] | |
private sealed class <MainAsync>d__1 : IAsyncStateMachine | |
{ | |
public int <>1__state; | |
public AsyncTaskMethodBuilder <>t__builder; | |
private CancellationTokenSource <cts>5__1; | |
private SomeABClass <a>5__2; | |
private long <l>5__3; | |
private long <>s__4; | |
private TaskAwaiter<long> <>u__1; | |
private void MoveNext() | |
{ | |
int num = <>1__state; | |
try | |
{ | |
TaskAwaiter<long> awaiter; | |
if (num != 0) | |
{ | |
<cts>5__1 = new CancellationTokenSource(); | |
<a>5__2 = new SomeABClass(); | |
awaiter = <a>5__2.AAA(<cts>5__1.Token).GetAwaiter(); | |
if (!awaiter.IsCompleted) | |
{ | |
num = (<>1__state = 0); | |
<>u__1 = awaiter; | |
<MainAsync>d__1 stateMachine = this; | |
<>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | |
return; | |
} | |
} | |
else | |
{ | |
awaiter = <>u__1; | |
<>u__1 = default(TaskAwaiter<long>); | |
num = (<>1__state = -1); | |
} | |
<>s__4 = awaiter.GetResult(); | |
<l>5__3 = <>s__4; | |
} | |
catch (Exception exception) | |
{ | |
<>1__state = -2; | |
<>t__builder.SetException(exception); | |
return; | |
} | |
<>1__state = -2; | |
<>t__builder.SetResult(); | |
} | |
void IAsyncStateMachine.MoveNext() | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in MoveNext | |
this.MoveNext(); | |
} | |
[DebuggerHidden] | |
private void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
} | |
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine | |
this.SetStateMachine(stateMachine); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[__DynamicallyInvokable] | |
[HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)] | |
public struct AsyncTaskMethodBuilder | |
{ | |
private static readonly Task<VoidTaskResult> s_cachedCompleted = AsyncTaskMethodBuilder<VoidTaskResult>.s_defaultResultTask; | |
private AsyncTaskMethodBuilder<VoidTaskResult> m_builder; | |
[__DynamicallyInvokable] | |
public Task Task | |
{ | |
[__DynamicallyInvokable] | |
get | |
{ | |
return m_builder.Task; | |
} | |
} | |
private object ObjectIdForDebugger => Task; | |
[__DynamicallyInvokable] | |
public static AsyncTaskMethodBuilder Create() | |
{ | |
return default(AsyncTaskMethodBuilder); | |
} | |
[SecuritySafeCritical] | |
[DebuggerStepThrough] | |
[__DynamicallyInvokable] | |
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine | |
{ | |
if (stateMachine == null) | |
{ | |
throw new ArgumentNullException("stateMachine"); | |
} | |
ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher); | |
RuntimeHelpers.PrepareConstrainedRegions(); | |
try | |
{ | |
ExecutionContext.EstablishCopyOnWriteScope(ref ecsw); | |
stateMachine.MoveNext(); | |
} | |
finally | |
{ | |
ecsw.Undo(); | |
} | |
} | |
[__DynamicallyInvokable] | |
public void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
m_builder.SetStateMachine(stateMachine); | |
} | |
[__DynamicallyInvokable] | |
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine | |
{ | |
m_builder.AwaitOnCompleted(ref awaiter, ref stateMachine); | |
} | |
[__DynamicallyInvokable] | |
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine | |
{ | |
m_builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); | |
} | |
[__DynamicallyInvokable] | |
public void SetResult() | |
{ | |
m_builder.SetResult(s_cachedCompleted); | |
} | |
[__DynamicallyInvokable] | |
public void SetException(Exception exception) | |
{ | |
m_builder.SetException(exception); | |
} | |
internal void SetNotificationForWaitCompletion(bool enabled) | |
{ | |
m_builder.SetNotificationForWaitCompletion(enabled); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public struct AsyncTaskMethodBuilder<TResult> | |
{ | |
private sealed class DebugFinalizableAsyncStateMachineBox<TStateMachine> : AsyncStateMachineBox<TStateMachine> where TStateMachine : notnull, IAsyncStateMachine | |
{ | |
~DebugFinalizableAsyncStateMachineBox() | |
{ | |
if (!base.IsCompleted) | |
{ | |
TplEventSource.Log.IncompleteAsyncMethod(this); | |
} | |
} | |
} | |
private class AsyncStateMachineBox<TStateMachine> : Task<TResult>, IAsyncStateMachineBox where TStateMachine : notnull, IAsyncStateMachine | |
{ | |
private static readonly ContextCallback s_callback = new ContextCallback(ExecutionContextCallback); | |
private Action _moveNextAction; | |
[AllowNull] | |
[MaybeNull] | |
public TStateMachine StateMachine; | |
public ExecutionContext Context; | |
public Action MoveNextAction => _moveNextAction ?? (_moveNextAction = new Action(MoveNext)); | |
private static void ExecutionContextCallback(object s) | |
{ | |
Unsafe.As<AsyncStateMachineBox<TStateMachine>>(s).StateMachine.MoveNext(); | |
} | |
internal sealed override void ExecuteFromThreadPool(Thread threadPoolThread) | |
{ | |
MoveNext(threadPoolThread); | |
} | |
public void MoveNext() | |
{ | |
MoveNext(null); | |
} | |
private void MoveNext(Thread threadPoolThread) | |
{ | |
bool loggingOn = AsyncCausalityTracer.LoggingOn; | |
if (loggingOn) | |
{ | |
AsyncCausalityTracer.TraceSynchronousWorkStart(this, CausalitySynchronousWork.Execution); | |
} | |
ExecutionContext context = Context; | |
if (context == null) | |
{ | |
StateMachine.MoveNext(); | |
} | |
else if (threadPoolThread == null) | |
{ | |
ExecutionContext.RunInternal(context, s_callback, this); | |
} | |
else | |
{ | |
ExecutionContext.RunFromThreadPoolDispatchLoop(threadPoolThread, context, s_callback, this); | |
} | |
if (base.IsCompleted) | |
{ | |
if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled) | |
{ | |
System.Threading.Tasks.Task.RemoveFromActiveTasks(this); | |
} | |
StateMachine = default(TStateMachine); | |
Context = null; | |
if (AsyncMethodBuilderCore.TrackAsyncMethodCompletion) | |
{ | |
GC.SuppressFinalize(this); | |
} | |
} | |
if (loggingOn) | |
{ | |
AsyncCausalityTracer.TraceSynchronousWorkCompletion(CausalitySynchronousWork.Execution); | |
} | |
} | |
IAsyncStateMachine IAsyncStateMachineBox.GetStateMachineObject() | |
{ | |
return StateMachine; | |
} | |
} | |
internal static readonly Task<TResult> s_defaultResultTask = AsyncTaskCache.CreateCacheableTask(default(TResult)); | |
private Task<TResult> m_task; | |
public Task<TResult> Task | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get | |
{ | |
return m_task ?? InitializeTaskAsPromise(); | |
} | |
} | |
internal object ObjectIdForDebugger => m_task ?? InitializeTaskAsStateMachineBox(); | |
public static AsyncTaskMethodBuilder<TResult> Create() | |
{ | |
return default(AsyncTaskMethodBuilder<TResult>); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
[DebuggerStepThrough] | |
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine | |
{ | |
AsyncMethodBuilderCore.Start(ref stateMachine); | |
} | |
public void SetStateMachine(IAsyncStateMachine stateMachine) | |
{ | |
AsyncMethodBuilderCore.SetStateMachine(stateMachine, m_task); | |
} | |
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine | |
{ | |
try | |
{ | |
awaiter.OnCompleted(GetStateMachineBox(ref stateMachine).MoveNextAction); | |
} | |
catch (Exception exception) | |
{ | |
System.Threading.Tasks.Task.ThrowAsync(exception, null); | |
} | |
} | |
[MethodImpl(MethodImplOptions.AggressiveOptimization)] | |
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine | |
{ | |
IAsyncStateMachineBox stateMachineBox = GetStateMachineBox(ref stateMachine); | |
if (default(TAwaiter) != null && awaiter is ITaskAwaiter) | |
{ | |
TaskAwaiter.UnsafeOnCompletedInternal(Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter).m_task, stateMachineBox, continueOnCapturedContext: true); | |
} | |
else if (default(TAwaiter) != null && awaiter is IConfiguredTaskAwaiter) | |
{ | |
ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter reference = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter); | |
TaskAwaiter.UnsafeOnCompletedInternal(reference.m_task, stateMachineBox, reference.m_continueOnCapturedContext); | |
} | |
else if (default(TAwaiter) != null && awaiter is IStateMachineBoxAwareAwaiter) | |
{ | |
try | |
{ | |
((IStateMachineBoxAwareAwaiter)(object)awaiter).AwaitUnsafeOnCompleted(stateMachineBox); | |
} | |
catch (Exception exception) | |
{ | |
System.Threading.Tasks.Task.ThrowAsync(exception, null); | |
} | |
} | |
else | |
{ | |
try | |
{ | |
awaiter.UnsafeOnCompleted(stateMachineBox.MoveNextAction); | |
} | |
catch (Exception exception2) | |
{ | |
System.Threading.Tasks.Task.ThrowAsync(exception2, null); | |
} | |
} | |
} | |
private IAsyncStateMachineBox GetStateMachineBox<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : notnull, IAsyncStateMachine | |
{ | |
ExecutionContext executionContext = ExecutionContext.Capture(); | |
AsyncStateMachineBox<TStateMachine> asyncStateMachineBox = m_task as AsyncStateMachineBox<TStateMachine>; | |
if (asyncStateMachineBox != null) | |
{ | |
if (asyncStateMachineBox.Context != executionContext) | |
{ | |
asyncStateMachineBox.Context = executionContext; | |
} | |
return asyncStateMachineBox; | |
} | |
AsyncStateMachineBox<IAsyncStateMachine> asyncStateMachineBox2 = m_task as AsyncStateMachineBox<IAsyncStateMachine>; | |
if (asyncStateMachineBox2 != null) | |
{ | |
if (asyncStateMachineBox2.StateMachine == null) | |
{ | |
Debugger.NotifyOfCrossThreadDependency(); | |
asyncStateMachineBox2.StateMachine = stateMachine; | |
} | |
asyncStateMachineBox2.Context = executionContext; | |
return asyncStateMachineBox2; | |
} | |
Debugger.NotifyOfCrossThreadDependency(); | |
AsyncStateMachineBox<TStateMachine> asyncStateMachineBox3 = (AsyncStateMachineBox<TStateMachine>)(m_task = (AsyncMethodBuilderCore.TrackAsyncMethodCompletion ? CreateDebugFinalizableAsyncStateMachineBox<TStateMachine>() : new AsyncStateMachineBox<TStateMachine>())); | |
asyncStateMachineBox3.StateMachine = stateMachine; | |
asyncStateMachineBox3.Context = executionContext; | |
if (AsyncCausalityTracer.LoggingOn) | |
{ | |
AsyncCausalityTracer.TraceOperationCreation(asyncStateMachineBox3, "Async: " + stateMachine.GetType().Name); | |
} | |
if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled) | |
{ | |
System.Threading.Tasks.Task.AddToActiveTasks(asyncStateMachineBox3); | |
} | |
return asyncStateMachineBox3; | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private static AsyncTaskMethodBuilder<TResult>.AsyncStateMachineBox<TStateMachine> CreateDebugFinalizableAsyncStateMachineBox<TStateMachine>() where TStateMachine : notnull, IAsyncStateMachine | |
{ | |
return new DebugFinalizableAsyncStateMachineBox<TStateMachine>(); | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private Task<TResult> InitializeTaskAsPromise() | |
{ | |
return m_task = new Task<TResult>(); | |
} | |
[MethodImpl(MethodImplOptions.NoInlining)] | |
private Task<TResult> InitializeTaskAsStateMachineBox() | |
{ | |
return m_task = (AsyncMethodBuilderCore.TrackAsyncMethodCompletion ? CreateDebugFinalizableAsyncStateMachineBox<IAsyncStateMachine>() : new AsyncStateMachineBox<IAsyncStateMachine>()); | |
} | |
public void SetResult(TResult result) | |
{ | |
if (m_task == null) | |
{ | |
m_task = GetTaskForResult(result); | |
} | |
else | |
{ | |
SetExistingTaskResult(result); | |
} | |
} | |
private void SetExistingTaskResult([AllowNull] TResult result) | |
{ | |
if (AsyncCausalityTracer.LoggingOn) | |
{ | |
AsyncCausalityTracer.TraceOperationCompletion(m_task, AsyncCausalityStatus.Completed); | |
} | |
if (!m_task.TrySetResult(result)) | |
{ | |
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); | |
} | |
} | |
internal void SetResult(Task<TResult> completedTask) | |
{ | |
if (m_task == null) | |
{ | |
m_task = completedTask; | |
} | |
else | |
{ | |
SetExistingTaskResult(default(TResult)); | |
} | |
} | |
public void SetException(Exception exception) | |
{ | |
if (exception == null) | |
{ | |
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); | |
} | |
Task<TResult> task = Task; | |
OperationCanceledException ex = exception as OperationCanceledException; | |
if (!((ex != null) ? task.TrySetCanceled(ex.CancellationToken, ex) : task.TrySetException(exception))) | |
{ | |
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted); | |
} | |
} | |
internal void SetNotificationForWaitCompletion(bool enabled) | |
{ | |
(m_task ?? InitializeTaskAsStateMachineBox()).SetNotificationForWaitCompletion(enabled); | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
internal static Task<TResult> GetTaskForResult(TResult result) | |
{ | |
if (default(TResult) != null) | |
{ | |
if (typeof(TResult) == typeof(bool)) | |
{ | |
Task<bool> value = ((bool)(object)result) ? AsyncTaskCache.TrueTask : AsyncTaskCache.FalseTask; | |
return Unsafe.As<Task<TResult>>(value); | |
} | |
if (typeof(TResult) == typeof(int)) | |
{ | |
int num = (int)(object)result; | |
if (num < 9 && num >= -1) | |
{ | |
Task<int> value2 = AsyncTaskCache.Int32Tasks[num - -1]; | |
return Unsafe.As<Task<TResult>>(value2); | |
} | |
} | |
else if ((typeof(TResult) == typeof(uint) && (uint)(object)result == 0) || (typeof(TResult) == typeof(byte) && (byte)(object)result == 0) || (typeof(TResult) == typeof(sbyte) && (sbyte)(object)result == 0) || (typeof(TResult) == typeof(char) && (char)(object)result == '\0') || (typeof(TResult) == typeof(long) && (long)(object)result == 0L) || (typeof(TResult) == typeof(ulong) && (ulong)(object)result == 0L) || (typeof(TResult) == typeof(short) && (short)(object)result == 0) || (typeof(TResult) == typeof(ushort) && (ushort)(object)result == 0) || (typeof(TResult) == typeof(IntPtr) && (IntPtr)0 == (IntPtr)(object)result) || (typeof(TResult) == typeof(UIntPtr) && (UIntPtr)0u == (UIntPtr)(object)result)) | |
{ | |
return s_defaultResultTask; | |
} | |
} | |
else if (result == null) | |
{ | |
return s_defaultResultTask; | |
} | |
return new Task<TResult>(result); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// System.Threading.Tasks.AwaitTaskContinuation | |
internal static void UnsafeScheduleAction(Action action, Task task) | |
{ | |
AwaitTaskContinuation awaitTaskContinuation = new AwaitTaskContinuation(action, flowExecutionContext: false); | |
TplEventSource log = TplEventSource.Log; | |
if (log.IsEnabled() && task != null) | |
{ | |
awaitTaskContinuation.m_continuationId = Task.NewId(); | |
log.AwaitTaskContinuationScheduled((task.ExecutingTaskScheduler ?? TaskScheduler.Default).Id, task.Id, awaitTaskContinuation.m_continuationId); | |
} | |
ThreadPool.UnsafeQueueUserWorkItemInternal(awaitTaskContinuation, preferLocal: true); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public readonly struct ConfiguredTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion, IConfiguredTaskAwaiter | |
{ | |
internal readonly Task m_task; | |
internal readonly bool m_continueOnCapturedContext; | |
public bool IsCompleted => m_task.IsCompleted; | |
internal ConfiguredTaskAwaiter(Task task, bool continueOnCapturedContext) | |
{ | |
m_task = task; | |
m_continueOnCapturedContext = continueOnCapturedContext; | |
} | |
public void OnCompleted(Action continuation) | |
{ | |
TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: true); | |
} | |
public void UnsafeOnCompleted(Action continuation) | |
{ | |
TaskAwaiter.OnCompletedInternal(m_task, continuation, m_continueOnCapturedContext, flowExecutionContext: false); | |
} | |
[StackTraceHidden] | |
public void GetResult() | |
{ | |
TaskAwaiter.ValidateEnd(m_task); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// System.Threading.Tasks.Task | |
private bool AddTaskContinuation(object tc, bool addBeforeOthers) | |
{ | |
if (IsCompleted) | |
{ | |
return false; | |
} | |
if (m_continuationObject != null || Interlocked.CompareExchange(ref m_continuationObject, tc, null) != null) | |
{ | |
return AddTaskContinuationComplex(tc, addBeforeOthers); | |
} | |
return true; | |
} | |
internal void SetContinuationForAwait(Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext) | |
{ | |
TaskContinuation taskContinuation = null; | |
if (continueOnCapturedContext) | |
{ | |
SynchronizationContext current = SynchronizationContext.Current; | |
if (current != null && current.GetType() != typeof(SynchronizationContext)) | |
{ | |
taskContinuation = new SynchronizationContextAwaitTaskContinuation(current, continuationAction, flowExecutionContext); | |
} | |
else | |
{ | |
TaskScheduler internalCurrent = TaskScheduler.InternalCurrent; | |
if (internalCurrent != null && internalCurrent != TaskScheduler.Default) | |
{ | |
taskContinuation = new TaskSchedulerAwaitTaskContinuation(internalCurrent, continuationAction, flowExecutionContext); | |
} | |
} | |
} | |
if (taskContinuation == null && flowExecutionContext) | |
{ | |
taskContinuation = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true); | |
} | |
if (taskContinuation != null) | |
{ | |
if (!AddTaskContinuation(taskContinuation, addBeforeOthers: false)) | |
{ | |
taskContinuation.Run(this, canInlineContinuationTask: false); | |
} | |
} | |
else if (!AddTaskContinuation(continuationAction, addBeforeOthers: false)) | |
{ | |
AwaitTaskContinuation.UnsafeScheduleAction(continuationAction, this); | |
} | |
} | |
internal void UnsafeSetContinuationForAwait(IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext) | |
{ | |
if (continueOnCapturedContext) | |
{ | |
SynchronizationContext current = SynchronizationContext.Current; | |
if (current != null && current.GetType() != typeof(SynchronizationContext)) | |
{ | |
SynchronizationContextAwaitTaskContinuation synchronizationContextAwaitTaskContinuation = new SynchronizationContextAwaitTaskContinuation(current, stateMachineBox.MoveNextAction, flowExecutionContext: false); | |
if (!AddTaskContinuation(synchronizationContextAwaitTaskContinuation, addBeforeOthers: false)) | |
{ | |
synchronizationContextAwaitTaskContinuation.Run(this, canInlineContinuationTask: false); | |
} | |
return; | |
} | |
TaskScheduler internalCurrent = TaskScheduler.InternalCurrent; | |
if (internalCurrent != null && internalCurrent != TaskScheduler.Default) | |
{ | |
TaskSchedulerAwaitTaskContinuation taskSchedulerAwaitTaskContinuation = new TaskSchedulerAwaitTaskContinuation(internalCurrent, stateMachineBox.MoveNextAction, flowExecutionContext: false); | |
if (!AddTaskContinuation(taskSchedulerAwaitTaskContinuation, addBeforeOthers: false)) | |
{ | |
taskSchedulerAwaitTaskContinuation.Run(this, canInlineContinuationTask: false); | |
} | |
return; | |
} | |
} | |
if (!AddTaskContinuation(stateMachineBox, addBeforeOthers: false)) | |
{ | |
ThreadPool.UnsafeQueueUserWorkItemInternal(stateMachineBox, preferLocal: true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public readonly struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion, ITaskAwaiter | |
{ | |
internal readonly Task m_task; | |
public bool IsCompleted => m_task.IsCompleted; | |
internal TaskAwaiter(Task task) | |
{ | |
m_task = task; | |
} | |
public void OnCompleted(Action continuation) | |
{ | |
OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: true); | |
} | |
public void UnsafeOnCompleted(Action continuation) | |
{ | |
OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: false); | |
} | |
[StackTraceHidden] | |
public void GetResult() | |
{ | |
ValidateEnd(m_task); | |
} | |
[StackTraceHidden] | |
internal static void ValidateEnd(Task task) | |
{ | |
if (task.IsWaitNotificationEnabledOrNotRanToCompletion) | |
{ | |
HandleNonSuccessAndDebuggerNotification(task); | |
} | |
} | |
[StackTraceHidden] | |
private static void HandleNonSuccessAndDebuggerNotification(Task task) | |
{ | |
if (!task.IsCompleted) | |
{ | |
bool flag = task.InternalWait(-1, default(CancellationToken)); | |
} | |
task.NotifyDebuggerOfWaitCompletionIfNecessary(); | |
if (!task.IsCompletedSuccessfully) | |
{ | |
ThrowForNonSuccess(task); | |
} | |
} | |
[StackTraceHidden] | |
private static void ThrowForNonSuccess(Task task) | |
{ | |
switch (task.Status) | |
{ | |
case TaskStatus.Canceled: | |
task.GetCancellationExceptionDispatchInfo()?.Throw(); | |
throw new TaskCanceledException(task); | |
case TaskStatus.Faulted: | |
{ | |
ReadOnlyCollection<ExceptionDispatchInfo> exceptionDispatchInfos = task.GetExceptionDispatchInfos(); | |
if (exceptionDispatchInfos.Count > 0) | |
{ | |
exceptionDispatchInfos[0].Throw(); | |
break; | |
} | |
throw task.Exception; | |
} | |
} | |
} | |
internal static void OnCompletedInternal(Task task, Action continuation, bool continueOnCapturedContext, bool flowExecutionContext) | |
{ | |
if (continuation == null) | |
{ | |
throw new ArgumentNullException("continuation"); | |
} | |
if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) | |
{ | |
continuation = OutputWaitEtwEvents(task, continuation); | |
} | |
task.SetContinuationForAwait(continuation, continueOnCapturedContext, flowExecutionContext); | |
} | |
internal static void UnsafeOnCompletedInternal(Task task, IAsyncStateMachineBox stateMachineBox, bool continueOnCapturedContext) | |
{ | |
if (TplEventSource.Log.IsEnabled() || Task.s_asyncDebuggingEnabled) | |
{ | |
task.SetContinuationForAwait(OutputWaitEtwEvents(task, stateMachineBox.MoveNextAction), continueOnCapturedContext, flowExecutionContext: false); | |
} | |
else | |
{ | |
task.UnsafeSetContinuationForAwait(stateMachineBox, continueOnCapturedContext); | |
} | |
} | |
private static Action OutputWaitEtwEvents(Task task, Action continuation) | |
{ | |
if (Task.s_asyncDebuggingEnabled) | |
{ | |
Task.AddToActiveTasks(task); | |
} | |
TplEventSource log = TplEventSource.Log; | |
if (log.IsEnabled()) | |
{ | |
Task internalCurrent = Task.InternalCurrent; | |
Task task2 = AsyncMethodBuilderCore.TryGetContinuationTask(continuation); | |
log.TaskWaitBegin(internalCurrent?.m_taskScheduler.Id ?? TaskScheduler.Default.Id, internalCurrent?.Id ?? 0, task.Id, TplEventSource.TaskWaitBehavior.Asynchronous, task2?.Id ?? 0); | |
} | |
return AsyncMethodBuilderCore.CreateContinuationWrapper(continuation, (Action<Action, Task>)delegate(Action innerContinuation, Task innerTask) | |
{ | |
if (Task.s_asyncDebuggingEnabled) | |
{ | |
Task.RemoveFromActiveTasks(innerTask); | |
} | |
TplEventSource log2 = TplEventSource.Log; | |
Guid oldActivityThatWillContinue = default(Guid); | |
bool flag = log2.IsEnabled(); | |
if (flag) | |
{ | |
Task internalCurrent2 = Task.InternalCurrent; | |
log2.TaskWaitEnd(internalCurrent2?.m_taskScheduler.Id ?? TaskScheduler.Default.Id, internalCurrent2?.Id ?? 0, innerTask.Id); | |
if (log2.TasksSetActivityIds && (innerTask.Options & (TaskCreationOptions)1024) != 0) | |
{ | |
EventSource.SetCurrentThreadActivityId(TplEventSource.CreateGuidForTaskID(innerTask.Id), out oldActivityThatWillContinue); | |
} | |
} | |
innerContinuation(); | |
if (flag) | |
{ | |
log2.TaskWaitContinuationComplete(innerTask.Id); | |
if (log2.TasksSetActivityIds && (innerTask.Options & (TaskCreationOptions)1024) != 0) | |
{ | |
EventSource.SetCurrentThreadActivityId(oldActivityThatWillContinue); | |
} | |
} | |
}, task); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public readonly struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion, ITaskAwaiter | |
{ | |
private readonly Task<TResult> m_task; | |
public bool IsCompleted => m_task.IsCompleted; | |
internal TaskAwaiter(Task<TResult> task) | |
{ | |
m_task = task; | |
} | |
public void OnCompleted(Action continuation) | |
{ | |
TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: true); | |
} | |
public void UnsafeOnCompleted(Action continuation) | |
{ | |
TaskAwaiter.OnCompletedInternal(m_task, continuation, continueOnCapturedContext: true, flowExecutionContext: false); | |
} | |
[StackTraceHidden] | |
public TResult GetResult() | |
{ | |
TaskAwaiter.ValidateEnd(m_task); | |
return m_task.ResultOnSuccess; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// System.Threading.ThreadPool | |
internal static void UnsafeQueueUserWorkItemInternal(object callBack, bool preferLocal) | |
{ | |
EnsureInitialized(); | |
ThreadPoolGlobals.workQueue.Enqueue(callBack, !preferLocal); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment