using System.Diagnostics; using System.Threading.Tasks.Sources; namespace KianaBH.KcpSharp.Base; internal class AsyncAutoResetEvent : IValueTaskSource { private bool _activeWait; private bool _isSet; private SpinLock _lock; private ManualResetValueTaskSourceCore _rvtsc; private bool _signaled; private T? _value; public AsyncAutoResetEvent() { _rvtsc = new ManualResetValueTaskSourceCore { RunContinuationsAsynchronously = true }; _lock = new SpinLock(); } T IValueTaskSource.GetResult(short token) { try { return _rvtsc.GetResult(token); } finally { _rvtsc.Reset(); var lockTaken = false; try { _lock.Enter(ref lockTaken); _activeWait = false; _signaled = false; } finally { if (lockTaken) _lock.Exit(); } } } ValueTaskSourceStatus IValueTaskSource.GetStatus(short token) { return _rvtsc.GetStatus(token); } void IValueTaskSource.OnCompleted(Action continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags) { _rvtsc.OnCompleted(continuation, state, token, flags); } public ValueTask WaitAsync() { var lockTaken = false; try { _lock.Enter(ref lockTaken); if (_activeWait) return new ValueTask( Task.FromException(new InvalidOperationException("Another thread is already waiting."))); if (_isSet) { _isSet = false; var value = _value!; _value = default; return new ValueTask(value); } _activeWait = true; Debug.Assert(!_signaled); return new ValueTask(this, _rvtsc.Version); } finally { if (lockTaken) _lock.Exit(); } } public void Set(T value) { var lockTaken = false; try { _lock.Enter(ref lockTaken); if (_activeWait && !_signaled) { _signaled = true; _rvtsc.SetResult(value); return; } _isSet = true; _value = value; } finally { if (lockTaken) _lock.Exit(); } } }