using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Capnp.Util { internal class StrictlyOrderedAwaitTask: INotifyCompletion { readonly Task _awaitedTask; object _lock; long _inOrder, _outOrder; public StrictlyOrderedAwaitTask(Task awaitedTask) { _awaitedTask = awaitedTask; _lock = new object(); } public StrictlyOrderedAwaitTask GetAwaiter() { return this; } public async void OnCompleted(Action continuation) { object safeLock = Volatile.Read(ref _lock); if (safeLock == null) { continuation(); return; } long sequence = Interlocked.Increment(ref _inOrder) - 1; try { if (_awaitedTask.IsCompleted) { Interlocked.Exchange(ref _lock, null); } await _awaitedTask; } catch { } finally { SpinWait.SpinUntil(() => { lock (safeLock) { if (Volatile.Read(ref _outOrder) != sequence) { return false; } Interlocked.Increment(ref _outOrder); continuation(); return true; } }); } } public bool IsCompleted => Volatile.Read(ref _lock) == null; public T GetResult() => _awaitedTask.GetAwaiter().GetResult(); public T Result => _awaitedTask.Result; public Task WrappedTask => _awaitedTask; } internal static class StrictlyOrderedTaskExtensions { public static StrictlyOrderedAwaitTask EnforceAwaitOrder(this Task task) { return new StrictlyOrderedAwaitTask(task); } } }