67 lines
1.7 KiB
C#
67 lines
1.7 KiB
C#
namespace System.Threading.Tasks;
|
|
|
|
public static class AsyncWaitHandle
|
|
{
|
|
public static Task WaitOneAsync(this WaitHandle waitHandle, CancellationToken cancellationToken = default)
|
|
{
|
|
WaitOneAsyncState state = new(waitHandle, cancellationToken);
|
|
return state.WaitOneAsync();
|
|
}
|
|
|
|
private class WaitOneAsyncState : IDisposable
|
|
{
|
|
private readonly CancellationTokenRegistration _cancellationTokenRegistration;
|
|
private readonly RegisteredWaitHandle _registeredWaitHandle;
|
|
private readonly TaskCompletionSource _tcs;
|
|
private bool _disposed;
|
|
|
|
public WaitOneAsyncState(WaitHandle waitHandle, CancellationToken cancellationToken)
|
|
{
|
|
_tcs = new();
|
|
_cancellationTokenRegistration = cancellationToken.Register((state, token) => ((WaitOneAsyncState)state!).Canceled(token), this);
|
|
_registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(waitHandle, (state, timeout) => ((WaitOneAsyncState)state!).Signaled(timeout), this, Timeout.Infinite, true);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_registeredWaitHandle.Unregister(default);
|
|
_cancellationTokenRegistration.Dispose();
|
|
|
|
_disposed = true;
|
|
}
|
|
|
|
public Task WaitOneAsync()
|
|
{
|
|
const TaskContinuationOptions options = TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.ExecuteSynchronously;
|
|
return _tcs.Task.ContinueWith((upstream, state) => ((WaitOneAsyncState)state!).Continuation(upstream), this, options).Unwrap();
|
|
}
|
|
|
|
private void Canceled(CancellationToken token)
|
|
{
|
|
_tcs.SetCanceled(token);
|
|
}
|
|
|
|
private Task Continuation(Task task)
|
|
{
|
|
Dispose();
|
|
return task;
|
|
}
|
|
|
|
private void Signaled(bool timeout)
|
|
{
|
|
if (timeout)
|
|
{
|
|
Canceled(CancellationToken.None);
|
|
}
|
|
else
|
|
{
|
|
_tcs.SetResult();
|
|
}
|
|
}
|
|
}
|
|
}
|