TimeProviderTaskExtensions
Provides extensions methods for Task operations with TimeProvider.
using System.Runtime.CompilerServices;
namespace System.Threading.Tasks
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public static class TimeProviderTaskExtensions
{
private sealed class DelayState : TaskCompletionSource<bool>
{
public ITimer Timer { get; set; }
public CancellationToken CancellationToken { get; }
public CancellationTokenRegistration Registration { get; set; }
public DelayState(CancellationToken cancellationToken)
{
CancellationToken = cancellationToken;
}
}
private sealed class WaitAsyncState : TaskCompletionSource<bool>
{
public readonly CancellationTokenSource ContinuationCancellation = new CancellationTokenSource();
public CancellationTokenRegistration Registration;
public ITimer Timer;
public CancellationToken CancellationToken { get; }
public WaitAsyncState(CancellationToken cancellationToken)
: base(TaskCreationOptions.RunContinuationsAsynchronously)
{
CancellationToken = cancellationToken;
}
}
public static Task Delay(this TimeProvider timeProvider, TimeSpan delay, CancellationToken cancellationToken = default(CancellationToken))
{
if (timeProvider == TimeProvider.System)
return Task.Delay(delay, cancellationToken);
ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider");
if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("delay");
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
if (delay == TimeSpan.Zero)
return Task.CompletedTask;
DelayState delayState2 = new DelayState(cancellationToken);
delayState2.Timer = timeProvider.CreateTimer(delegate(object delayState) {
DelayState obj2 = (DelayState)delayState;
obj2.TrySetResult(true);
obj2.Registration.Dispose();
obj2.Timer?.Dispose();
}, delayState2, delay, Timeout.InfiniteTimeSpan);
delayState2.Registration = cancellationToken.Register(delegate(object delayState) {
DelayState delayState3 = (DelayState)delayState;
ThreadPool.UnsafeQueueUserWorkItem(delegate(object state) {
DelayState obj = (DelayState)state;
obj.TrySetCanceled(obj.CancellationToken);
}, delayState3);
delayState3.Registration.Dispose();
delayState3.Timer?.Dispose();
}, delayState2);
if (delayState2.Task.IsCompleted) {
delayState2.Registration.Dispose();
delayState2.Timer.Dispose();
}
return delayState2.Task;
}
public static Task WaitAsync(this Task task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default(CancellationToken))
{
ExceptionPolyfills.ThrowIfNull(task, "task");
if (timeout != Timeout.InfiniteTimeSpan && timeout < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("timeout");
ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider");
if (task.IsCompleted)
return task;
if (timeout == Timeout.InfiniteTimeSpan && !cancellationToken.CanBeCanceled)
return task;
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
if (timeout == TimeSpan.Zero)
return Task.FromException(new TimeoutException());
WaitAsyncState waitAsyncState = new WaitAsyncState(cancellationToken);
waitAsyncState.Timer = timeProvider.CreateTimer(delegate(object s) {
WaitAsyncState obj2 = (WaitAsyncState)s;
obj2.TrySetException(new TimeoutException());
obj2.Registration.Dispose();
obj2.Timer?.Dispose();
obj2.ContinuationCancellation.Cancel();
}, waitAsyncState, timeout, Timeout.InfiniteTimeSpan);
task.ContinueWith(delegate(Task t, object s) {
WaitAsyncState waitAsyncState2 = (WaitAsyncState)s;
if (t.IsFaulted)
waitAsyncState2.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled) {
waitAsyncState2.TrySetCanceled();
} else {
waitAsyncState2.TrySetResult(true);
}
waitAsyncState2.Registration.Dispose();
waitAsyncState2.Timer?.Dispose();
}, waitAsyncState, waitAsyncState.ContinuationCancellation.Token, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
waitAsyncState.Registration = cancellationToken.Register(delegate(object s) {
WaitAsyncState obj = (WaitAsyncState)s;
obj.TrySetCanceled(obj.CancellationToken);
obj.Timer?.Dispose();
obj.ContinuationCancellation.Cancel();
}, waitAsyncState);
if (waitAsyncState.Task.IsCompleted) {
waitAsyncState.Registration.Dispose();
waitAsyncState.Timer.Dispose();
}
return waitAsyncState.Task;
}
[AsyncStateMachine(typeof(<WaitAsync>d__4<>))]
public static Task<TResult> WaitAsync<[System.Runtime.CompilerServices.Nullable(2)] TResult>(this Task<TResult> task, TimeSpan timeout, TimeProvider timeProvider, CancellationToken cancellationToken = default(CancellationToken))
{
<WaitAsync>d__4<TResult> stateMachine = default(<WaitAsync>d__4<TResult>);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<TResult>.Create();
stateMachine.task = task;
stateMachine.timeout = timeout;
stateMachine.timeProvider = timeProvider;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static CancellationTokenSource CreateCancellationTokenSource(this TimeProvider timeProvider, TimeSpan delay)
{
ExceptionPolyfills.ThrowIfNull(timeProvider, "timeProvider");
if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("delay");
if (timeProvider == TimeProvider.System)
return new CancellationTokenSource(delay);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
ITimer state = timeProvider.CreateTimer(delegate(object s) {
try {
((CancellationTokenSource)s).Cancel();
} catch (ObjectDisposedException) {
}
}, cancellationTokenSource, delay, Timeout.InfiniteTimeSpan);
cancellationTokenSource.Token.Register(delegate(object t) {
((ITimer)t).Dispose();
}, state);
return cancellationTokenSource;
}
}
}