using System; using System.Threading; using System.Threading.Tasks; namespace MQTTnet.Internal { // From Stephen Toub (https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/) public sealed class AsyncLock : IDisposable { private readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1); private readonly Task m_releaser; public AsyncLock() { m_releaser = Task.FromResult((IDisposable)new Releaser(this)); } public Task LockAsync(CancellationToken cancellationToken) { var wait = m_semaphore.WaitAsync(cancellationToken); return wait.IsCompleted ? m_releaser : wait.ContinueWith((_, state) => (IDisposable)state, m_releaser.Result, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public void Dispose() { this.m_semaphore?.Dispose(); } private sealed class Releaser : IDisposable { private readonly AsyncLock m_toRelease; internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; } public void Dispose() { m_toRelease.m_semaphore.Release(); } } } }