You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
7.3 KiB
169 lines
7.3 KiB
5 years ago
|
#if NET20 || NET30 || NET35 || !NET_4_6
|
||
|
|
||
|
using System.Diagnostics.Contracts;
|
||
|
|
||
|
namespace System.Threading.Tasks
|
||
|
{
|
||
|
public partial class Task
|
||
|
{
|
||
|
/// <summary>A task that's already been completed successfully.</summary>
|
||
|
private static Task _completedTask;
|
||
|
|
||
|
/// <summary>Gets a task that's already been completed successfully.</summary>
|
||
|
/// <remarks>May not always return the same instance.</remarks>
|
||
|
internal static Task CompletedTask
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
var completedTask = _completedTask;
|
||
|
if (completedTask == null)
|
||
|
{
|
||
|
_completedTask = completedTask = CreateCompletedTask();
|
||
|
}
|
||
|
return completedTask;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a Task that will complete after a time delay.
|
||
|
/// </summary>
|
||
|
/// <param name="delay">The time span to wait before completing the returned Task</param>
|
||
|
/// <returns>A Task that represents the time delay</returns>
|
||
|
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
||
|
/// The <paramref name="delay"/> is less than -1 or greater than Int32.MaxValue.
|
||
|
/// </exception>
|
||
|
/// <remarks>
|
||
|
/// After the specified time delay, the Task is completed in RanToCompletion state.
|
||
|
/// </remarks>
|
||
|
public static Task Delay(TimeSpan delay)
|
||
|
{
|
||
|
return Delay(delay, default(CancellationToken));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a Task that will complete after a time delay.
|
||
|
/// </summary>
|
||
|
/// <param name="delay">The time span to wait before completing the returned Task</param>
|
||
|
/// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned Task</param>
|
||
|
/// <returns>A Task that represents the time delay</returns>
|
||
|
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
||
|
/// The <paramref name="delay"/> is less than -1 or greater than Int32.MaxValue.
|
||
|
/// </exception>
|
||
|
/// <exception cref="T:System.ObjectDisposedException">
|
||
|
/// The provided <paramref name="cancellationToken"/> has already been disposed.
|
||
|
/// </exception>
|
||
|
/// <remarks>
|
||
|
/// If the cancellation token is signaled before the specified time delay, then the Task is completed in
|
||
|
/// Canceled state. Otherwise, the Task is completed in RanToCompletion state once the specified time
|
||
|
/// delay has expired.
|
||
|
/// </remarks>
|
||
|
public static Task Delay(TimeSpan delay, CancellationToken cancellationToken)
|
||
|
{
|
||
|
var totalMilliseconds = (long)delay.TotalMilliseconds;
|
||
|
if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException("delay", "The value needs to translate in milliseconds to - 1(signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue");
|
||
|
}
|
||
|
|
||
|
return Delay((int)totalMilliseconds, cancellationToken);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a Task that will complete after a time delay.
|
||
|
/// </summary>
|
||
|
/// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param>
|
||
|
/// <returns>A Task that represents the time delay</returns>
|
||
|
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
||
|
/// The <paramref name="millisecondsDelay"/> is less than -1.
|
||
|
/// </exception>
|
||
|
/// <remarks>
|
||
|
/// After the specified time delay, the Task is completed in RanToCompletion state.
|
||
|
/// </remarks>
|
||
|
public static Task Delay(int millisecondsDelay)
|
||
|
{
|
||
|
return Delay(millisecondsDelay, default(CancellationToken));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a Task that will complete after a time delay.
|
||
|
/// </summary>
|
||
|
/// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param>
|
||
|
/// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned Task</param>
|
||
|
/// <returns>A Task that represents the time delay</returns>
|
||
|
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
||
|
/// The <paramref name="millisecondsDelay"/> is less than -1.
|
||
|
/// </exception>
|
||
|
/// <exception cref="T:System.ObjectDisposedException">
|
||
|
/// The provided <paramref name="cancellationToken"/> has already been disposed.
|
||
|
/// </exception>
|
||
|
/// <remarks>
|
||
|
/// If the cancellation token is signaled before the specified time delay, then the Task is completed in
|
||
|
/// Canceled state. Otherwise, the Task is completed in RanToCompletion state once the specified time
|
||
|
/// delay has expired.
|
||
|
/// </remarks>
|
||
|
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken)
|
||
|
{
|
||
|
// Throw on non-sensical time
|
||
|
if (millisecondsDelay < -1)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException("millisecondsDelay", "The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer.");
|
||
|
}
|
||
|
Contract.EndContractBlock();
|
||
|
// some short-cuts in case quick completion is in order
|
||
|
if (cancellationToken.IsCancellationRequested)
|
||
|
{
|
||
|
// return a Task created as already-Canceled
|
||
|
return FromCancellation(cancellationToken);
|
||
|
}
|
||
|
if (millisecondsDelay == 0)
|
||
|
{
|
||
|
// return a Task created as already-RanToCompletion
|
||
|
return CompletedTask;
|
||
|
}
|
||
|
var source = new TaskCompletionSource<bool>();
|
||
|
if (millisecondsDelay > 0)
|
||
|
{
|
||
|
var timeout =
|
||
|
new LinqInternal.Threading.Timeout
|
||
|
(
|
||
|
() =>
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
source.SetResult(true);
|
||
|
}
|
||
|
catch (InvalidOperationException exception)
|
||
|
{
|
||
|
// Already cancelled
|
||
|
GC.KeepAlive(exception);
|
||
|
}
|
||
|
},
|
||
|
millisecondsDelay,
|
||
|
cancellationToken
|
||
|
);
|
||
|
source.Task.SetPromiseCheck(() => timeout.CheckRemaining());
|
||
|
}
|
||
|
if (cancellationToken.CanBeCanceled)
|
||
|
{
|
||
|
cancellationToken.Register
|
||
|
(
|
||
|
() =>
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
source.SetCanceled();
|
||
|
}
|
||
|
catch (InvalidOperationException exception)
|
||
|
{
|
||
|
// Already timeout
|
||
|
GC.KeepAlive(exception);
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
return source.Task;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|