Last active
February 13, 2026 11:00
-
-
Save aetos382/da0df99431222a9d8f47c8eece3605db to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| using System.Collections.Concurrent; | |
| using System.Diagnostics; | |
| using System.Runtime.CompilerServices; | |
| using System.Runtime.ExceptionServices; | |
| Console.WriteLine(await S()); | |
| Console.WriteLine(await T()); | |
| try | |
| { | |
| var myTask = MyT(); | |
| ((ICriticalNotifyCompletion)myTask.GetAwaiter()).UnsafeOnCompleted(static () => Console.WriteLine("co1")); | |
| ((ICriticalNotifyCompletion)myTask.GetAwaiter()).UnsafeOnCompleted(static () => throw new Exception("ah")); | |
| ((ICriticalNotifyCompletion)myTask.GetAwaiter()).UnsafeOnCompleted(static () => Console.WriteLine("co2")); | |
| Console.WriteLine("X"); | |
| await myTask; | |
| } | |
| catch (Exception e) | |
| { | |
| Console.WriteLine(e); | |
| throw; | |
| } | |
| partial class Program | |
| { | |
| private static async Task<int> S() | |
| { | |
| var i = 100; | |
| i = await IncrementAsync(i, "step 1"); | |
| i = await IncrementAsync(i, "step 2", false); | |
| i = await IncrementAsync(i, "step 3"); | |
| return i; | |
| } | |
| private static async MyTask<int> T() | |
| { | |
| var i = 100; | |
| i = await IncrementAsync(i, "step 1"); | |
| i = await IncrementAsync(i, "step 2", false); | |
| i = await IncrementAsync(i, "step 3"); | |
| return i; | |
| } | |
| [AsyncStateMachine(typeof(StateMachine))] | |
| private static MyTask<int> MyT() | |
| { | |
| var builder = MyTaskMethodBuilder<int>.Create(); | |
| var stateMachine = new StateMachine(builder); | |
| builder.Start(ref stateMachine); | |
| var task = builder.Task; | |
| return task; | |
| } | |
| private static async Task<int> IncrementAsync(int value, string label, bool completeSynchronously = true) | |
| { | |
| if (!completeSynchronously) | |
| { | |
| await Task.Delay(1); | |
| } | |
| return value + 1; | |
| } | |
| } | |
| [AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))] | |
| class MyTask<T> | |
| { | |
| public static MyTask<T> FromResult(T result) | |
| { | |
| return new() | |
| { | |
| _result = result, | |
| _state = MyTaskState.Success | |
| }; | |
| } | |
| public static MyTask<T> FromException(Exception exception) | |
| { | |
| return new() | |
| { | |
| _exception = exception, | |
| _state = MyTaskState.Failed | |
| }; | |
| } | |
| public MyTaskAwaiter<T> GetAwaiter() | |
| { | |
| return new MyTaskAwaiter<T>(this); | |
| } | |
| public T GetResult() | |
| { | |
| if (!IsCompleted) | |
| { | |
| var block = _block = new ManualResetEventSlim(); | |
| block.Wait(); | |
| block.Dispose(); | |
| } | |
| switch (_state) | |
| { | |
| case MyTaskState.Success: | |
| return _result!; | |
| case MyTaskState.Failed: | |
| ExceptionDispatchInfo.Throw(_exception!); | |
| throw new UnreachableException(); | |
| default: | |
| throw new InvalidOperationException(); | |
| } | |
| } | |
| private MyTaskState _state = MyTaskState.RanToCompletion; | |
| private T? _result; | |
| private Exception? _exception; | |
| private ManualResetEventSlim? _block; | |
| private readonly ConcurrentQueue<Action> _continuationActions = new(); | |
| private readonly ConcurrentQueue<Action> _unsafeContinuationActions = new(); | |
| internal void SetResult(T result) | |
| { | |
| if (Interlocked.CompareExchange(ref _state, MyTaskState.Success, MyTaskState.RanToCompletion) != MyTaskState.RanToCompletion) | |
| { | |
| throw new InvalidOperationException(); | |
| } | |
| _result = result; | |
| RunCallbacks(); | |
| _block?.Set(); | |
| } | |
| internal void SetException(Exception exception) | |
| { | |
| if (Interlocked.CompareExchange(ref _state, MyTaskState.Failed, MyTaskState.RanToCompletion) != MyTaskState.RanToCompletion) | |
| { | |
| throw new InvalidOperationException(); | |
| } | |
| _exception = exception; | |
| RunCallbacks(); | |
| _block?.Set(); | |
| } | |
| internal bool IsCompleted => _state is not MyTaskState.RanToCompletion; | |
| private void RunCallbacks() | |
| { | |
| var exceptions = new List<Exception>(); | |
| while (_continuationActions.TryDequeue(out var action)) | |
| { | |
| try | |
| { | |
| action(); | |
| } | |
| catch (Exception e) | |
| { | |
| exceptions.Add(e); | |
| } | |
| } | |
| using var flowControl = ExecutionContext.SuppressFlow(); | |
| while (_unsafeContinuationActions.TryDequeue(out var action)) | |
| { | |
| try | |
| { | |
| action(); | |
| } | |
| catch (Exception e) | |
| { | |
| exceptions.Add(e); | |
| } | |
| } | |
| if (exceptions.Count != 0) | |
| { | |
| throw new AggregateException(exceptions); | |
| } | |
| } | |
| internal void OnCompleted(Action continuation) | |
| { | |
| _continuationActions.Enqueue(continuation); | |
| if (IsCompleted) | |
| { | |
| RunCallbacks(); | |
| } | |
| } | |
| internal void UnsafeOnCompleted(Action continuation) | |
| { | |
| _unsafeContinuationActions.Enqueue(continuation); | |
| if (IsCompleted) | |
| { | |
| RunCallbacks(); | |
| } | |
| } | |
| } | |
| public enum MyTaskState | |
| { | |
| RanToCompletion, | |
| Success, | |
| Failed | |
| } | |
| public class MyTaskAwaiter<T> : | |
| ICriticalNotifyCompletion | |
| { | |
| private readonly MyTask<T> _task; | |
| internal MyTaskAwaiter(MyTask<T> task) | |
| { | |
| _task = task; | |
| } | |
| public bool IsCompleted => _task.IsCompleted; | |
| void INotifyCompletion.OnCompleted(Action continuation) | |
| { | |
| _task.OnCompleted(continuation); | |
| } | |
| void ICriticalNotifyCompletion.UnsafeOnCompleted(Action continuation) | |
| { | |
| _task.UnsafeOnCompleted(continuation); | |
| } | |
| public T GetResult() | |
| { | |
| return _task.GetResult(); | |
| } | |
| } | |
| class MyTaskMethodBuilder<T> | |
| { | |
| public static MyTaskMethodBuilder<T> Create() | |
| { | |
| return new(); | |
| } | |
| private readonly MyTask<T> _task = new(); | |
| public MyTask<T> Task => _task; | |
| public void SetException(Exception exception) | |
| { | |
| _task.SetException(exception); | |
| } | |
| public void SetResult(T result) | |
| { | |
| _task.SetResult(result); | |
| } | |
| public void AwaitOnCompleted<TAwaiter, TStateMachine>( | |
| ref TAwaiter awaiter, | |
| ref TStateMachine stateMachine) | |
| where TAwaiter : INotifyCompletion | |
| where TStateMachine : IAsyncStateMachine | |
| { | |
| awaiter.OnCompleted(stateMachine.MoveNext); | |
| } | |
| public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( | |
| ref TAwaiter awaiter, | |
| ref TStateMachine stateMachine) | |
| where TAwaiter : ICriticalNotifyCompletion | |
| where TStateMachine : IAsyncStateMachine | |
| { | |
| awaiter.UnsafeOnCompleted(stateMachine.MoveNext); | |
| } | |
| public void Start<TStateMachine>( | |
| ref TStateMachine stateMachine) | |
| where TStateMachine : IAsyncStateMachine | |
| { | |
| stateMachine.MoveNext(); | |
| } | |
| public void SetStateMachine( | |
| IAsyncStateMachine stateMachine) | |
| { | |
| // do nothing | |
| } | |
| } | |
| partial class Program | |
| { | |
| class StateMachine : | |
| IAsyncStateMachine | |
| { | |
| private readonly MyTaskMethodBuilder<int> _builder; | |
| private int _state = 0; | |
| private ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter _awaiter1; | |
| private ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _awaiter2; | |
| private ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter _awaiter3; | |
| private int _result; | |
| public StateMachine( | |
| MyTaskMethodBuilder<int> builder) | |
| { | |
| ArgumentNullException.ThrowIfNull(builder); | |
| this._builder = builder; | |
| } | |
| void IAsyncStateMachine.MoveNext() | |
| { | |
| var builder = _builder; | |
| try | |
| { | |
| int result; | |
| ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter awaiter1; | |
| ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter2; | |
| ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter awaiter3; | |
| switch (_state) | |
| { | |
| case 0: | |
| result = 100; | |
| awaiter1 = IncrementAsync(result, "step 1").ConfigureAwait(false).GetAwaiter(); | |
| if (!awaiter1.IsCompleted) | |
| { | |
| _state = 1; | |
| _awaiter1 = awaiter1; | |
| _result = result; | |
| var stateMachine = this; | |
| builder.AwaitUnsafeOnCompleted(ref awaiter1, ref stateMachine); | |
| return; | |
| } | |
| step1_completed: | |
| result = awaiter1.GetResult(); | |
| awaiter2 = Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false).GetAwaiter(); | |
| if (!awaiter2.IsCompleted) | |
| { | |
| _state = 2; | |
| _awaiter2 = awaiter2; | |
| _result = result; | |
| var stateMachine = this; | |
| builder.AwaitUnsafeOnCompleted(ref awaiter2, ref stateMachine); | |
| return; | |
| } | |
| step2_completed: | |
| awaiter2.GetResult(); | |
| awaiter3 = IncrementAsync(result, "step 3").ConfigureAwait(false).GetAwaiter(); | |
| if (!awaiter3.IsCompleted) | |
| { | |
| _state = 3; | |
| _awaiter3 = awaiter3; | |
| _result = result; | |
| var stateMachine = this; | |
| builder.AwaitUnsafeOnCompleted(ref awaiter3, ref stateMachine); | |
| return; | |
| } | |
| step3_completed: | |
| goto final; | |
| case 1: | |
| awaiter1 = _awaiter1; | |
| result = _result; | |
| goto step1_completed; | |
| case 2: | |
| awaiter2 = _awaiter2; | |
| result = _result; | |
| goto step2_completed; | |
| case 3: | |
| awaiter3 = _awaiter3; | |
| result = _result; | |
| goto step3_completed; | |
| final: | |
| result = awaiter3.GetResult(); | |
| builder.SetResult(result); | |
| return; | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| builder.SetException(e); | |
| } | |
| } | |
| void IAsyncStateMachine.SetStateMachine( | |
| IAsyncStateMachine stateMachine) | |
| { | |
| // do nothing | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment