// awaited twice concurrently), _continuationState might get erroneously overwritten.
// To minimize the chances of that, we check preemptively whether _continuation
// is already set to something other than the completion sentinel.
- object currentContinuation = _continuation;
- if (currentContinuation != null &&
- !ReferenceEquals(currentContinuation, ManualResetValueTaskSourceCoreShared.s_sentinel))
+
+ object oldContinuation = _continuation;
+ if (oldContinuation == null)
{
- ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+ _continuationState = state;
+ oldContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null);
}
- _continuationState = state;
- Action<object> oldContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null);
if (oldContinuation != null)
{
+ // Operation already completed, so we need to queue the supplied callback.
+ if (!ReferenceEquals(oldContinuation, ManualResetValueTaskSourceCoreShared.s_sentinel))
+ {
+ ManualResetValueTaskSourceCoreShared.ThrowInvalidOperationException();
+ }
+
switch (_capturedContext)
{
case null:
}
_completed = true;
- if (Interlocked.CompareExchange(ref _continuation, ManualResetValueTaskSourceCoreShared.s_sentinel, null) != null)
+ if (_continuation != null || Interlocked.CompareExchange(ref _continuation, ManualResetValueTaskSourceCoreShared.s_sentinel, null) != null)
{
if (_executionContext != null)
{