ManualResetValueTaskSourceCore<TResult>
Provides the core logic for implementing a manual-reset IValueTaskSource or IValueTaskSource<T>.
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
namespace System.Threading.Tasks.Sources
{
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public struct ManualResetValueTaskSourceCore<[System.Runtime.CompilerServices.Nullable(2)] TResult>
{
private Action<object> _continuation;
private object _continuationState;
private ExecutionContext _executionContext;
private object _capturedContext;
private bool _completed;
private TResult _result;
private ExceptionDispatchInfo _error;
private short _version;
public bool RunContinuationsAsynchronously {
[System.Runtime.CompilerServices.IsReadOnly]
get;
set;
}
public short Version => _version;
public void Reset()
{
_version++;
_completed = false;
_result = default(TResult);
_error = null;
_executionContext = null;
_capturedContext = null;
_continuation = null;
_continuationState = null;
}
public void SetResult(TResult result)
{
_result = result;
SignalCompletion();
}
public void SetException(Exception error)
{
_error = ExceptionDispatchInfo.Capture(error);
SignalCompletion();
}
public ValueTaskSourceStatus GetStatus(short token)
{
ValidateToken(token);
if (_continuation != null && _completed) {
if (_error != null) {
if (!(_error.SourceException is OperationCanceledException))
return ValueTaskSourceStatus.Faulted;
return ValueTaskSourceStatus.Canceled;
}
return ValueTaskSourceStatus.Succeeded;
}
return ValueTaskSourceStatus.Pending;
}
public TResult GetResult(short token)
{
ValidateToken(token);
if (!_completed)
throw new InvalidOperationException();
_error?.Throw();
return _result;
}
[System.Runtime.CompilerServices.NullableContext(2)]
public void OnCompleted([System.Runtime.CompilerServices.Nullable(new byte[] {
1,
2
})] Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
{
if (continuation == null)
throw new ArgumentNullException("continuation");
ValidateToken(token);
if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
_executionContext = ExecutionContext.Capture();
if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) {
SynchronizationContext current = SynchronizationContext.Current;
if (current != null && current.GetType() != typeof(SynchronizationContext))
_capturedContext = current;
else {
TaskScheduler current2 = TaskScheduler.Current;
if (current2 != TaskScheduler.Default)
_capturedContext = current2;
}
}
object obj = _continuation;
if (obj == null) {
_continuationState = state;
obj = Interlocked.CompareExchange<Action<object>>(ref _continuation, continuation, (Action<object>)null);
}
if (obj != null) {
if (obj != System.Threading.Tasks.Sources.ManualResetValueTaskSourceCoreShared.s_sentinel)
throw new InvalidOperationException();
object capturedContext = _capturedContext;
if (capturedContext != null) {
SynchronizationContext synchronizationContext = capturedContext as SynchronizationContext;
if (synchronizationContext == null) {
TaskScheduler taskScheduler = capturedContext as TaskScheduler;
if (taskScheduler != null)
Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler);
} else
synchronizationContext.Post(delegate(object s) {
Tuple<Action<object>, object> tuple = (Tuple<Action<object>, object>)s;
tuple.Item1(tuple.Item2);
}, Tuple.Create<Action<object>, object>(continuation, state));
} else
Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
}
private void ValidateToken(short token)
{
if (token != _version)
throw new InvalidOperationException();
}
private void SignalCompletion()
{
if (_completed)
throw new InvalidOperationException();
_completed = true;
if (_continuation != null || Interlocked.CompareExchange<Action<object>>(ref _continuation, System.Threading.Tasks.Sources.ManualResetValueTaskSourceCoreShared.s_sentinel, (Action<object>)null) != null) {
if (_executionContext != null)
ExecutionContext.Run(_executionContext, delegate(object s) {
((ManualResetValueTaskSourceCore<TResult>)s).InvokeContinuation();
}, this);
else
InvokeContinuation();
}
}
private void InvokeContinuation()
{
object capturedContext = _capturedContext;
if (capturedContext != null) {
SynchronizationContext synchronizationContext = capturedContext as SynchronizationContext;
if (synchronizationContext == null) {
TaskScheduler taskScheduler = capturedContext as TaskScheduler;
if (taskScheduler != null)
Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, taskScheduler);
} else
synchronizationContext.Post(delegate(object s) {
Tuple<Action<object>, object> tuple = (Tuple<Action<object>, object>)s;
tuple.Item1(tuple.Item2);
}, Tuple.Create<Action<object>, object>(_continuation, _continuationState));
} else if (RunContinuationsAsynchronously) {
Task.Factory.StartNew(_continuation, _continuationState, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
} else {
_continuation(_continuationState);
}
}
}
}