public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } ValidateToken(token); if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { _executionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { SynchronizationContext sc = SynchronizationContext.Current; if (sc != null && sc.GetType() != typeof(SynchronizationContext)) { _capturedContext = sc; } else { TaskScheduler ts = TaskScheduler.Current; if (ts != TaskScheduler.Default) { _capturedContext = ts; } } } _continuationState = state; if (Interlocked.CompareExchange(ref _continuation, continuation, null) != null) { _executionContext = null; object cc = _capturedContext; _capturedContext = null; switch (cc) { case null: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); break; case SynchronizationContext sc: sc.Post(s => { var tuple = (Tuple <Action <object>, object>)s; tuple.Item1(tuple.Item2); }, Tuple.Create(continuation, state)); break; case TaskScheduler ts: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); break; } } }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => Flags = flags;
void IValueTaskSource <T> .OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { _taskSourceCore.OnCompleted(continuation, state, token, flags); }
void IValueTaskSource <TPackageInfo> .OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { _packageTaskSource.OnCompleted(continuation, state, token, flags); }
/// <summary>Schedules the continuation action for this operation.</summary> /// <param name="continuation">The continuation to invoke when the operation has completed.</param> /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param> /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param> /// <param name="flags">The flags describing the behavior of the continuation.</param> public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } ValidateToken(token); if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { _executionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { SynchronizationContext sc = SynchronizationContext.Current; if (sc != null && sc.GetType() != typeof(SynchronizationContext)) { _capturedContext = sc; } else { TaskScheduler ts = TaskScheduler.Current; if (ts != TaskScheduler.Default) { _capturedContext = ts; } } } // We need to set the continuation state before we swap in the delegate, so that // if there's a race between this and SetResult/Exception and SetResult/Exception // sees the _continuation as non-null, it'll be able to invoke it with the state // stored here. However, this also means that if this is used incorrectly (e.g. // 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 oldContinuation = _continuation; if (oldContinuation == null) { _continuationState = state; 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)) { ThrowHelper.ThrowInvalidOperationException(); } switch (_capturedContext) { case null: if (_executionContext != null) { ThreadPool.QueueUserWorkItem(continuation, state, preferLocal: true); } else { ThreadPool.UnsafeQueueUserWorkItem(continuation, state, preferLocal: true); } break; case SynchronizationContext sc: sc.Post(s => { var tuple = (Tuple <Action <object>, object>)s; tuple.Item1(tuple.Item2); }, Tuple.Create(continuation, state)); break; case TaskScheduler ts: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); break; } } }
/// <summary> /// Schedules the continuation action for this operation. /// </summary> public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } _mre.OnCompleted(continuation, state, token, flags); }
private static void CaptureThreadContext(ref ContinuationContext destination, ValueTaskSourceOnCompletedFlags flags) { if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { destination.ExecutionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { SynchronizationContext?sc = SynchronizationContext.Current; if (sc != null && sc.GetType() != typeof(SynchronizationContext)) { destination.Scheduler = sc; } else { TaskScheduler ts = TaskScheduler.Default; if (ts != TaskScheduler.Default) { destination.Scheduler = ts; } } } }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { _task.GetAwaiter().UnsafeOnCompleted(() => continuation(state)); _tcs.TrySetResult(); }
void IValueTaskSource <bool> .OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _valueOrEndPromise.OnCompleted(continuation, state, token, flags);
void IValueTaskSource <bool> .OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { this._taskHelper.OnCompleted(continuation, state, token, flags); }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _pipe.OnReadAsyncCompleted(continuation, state, flags);
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { ValidateToken(token); _continuation = continuation; _state = state; foreach (var task in _tasks) { WaitTask(task); } }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (Interlocked.CompareExchange(ref this.continuation, continuation, ContinuationSentinel.AvailableContinuation) != ContinuationSentinel.AvailableContinuation) { throw new InvalidOperationException("does not allow multiple await."); } this.state = state; if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) == ValueTaskSourceOnCompletedFlags.FlowExecutionContext) { execContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) == ValueTaskSourceOnCompletedFlags.UseSchedulingContext) { syncContext = SynchronizationContext.Current; } if (GetStatus(token) != ValueTaskSourceStatus.Pending) { TryInvokeContinuation(); } }
/// <summary>Schedules the continuation action for this operation.</summary> /// <param name="continuation">The continuation to invoke when the operation has completed.</param> /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param> /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param> /// <param name="flags">The flags describing the behavior of the continuation.</param> public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } ValidateToken(token); if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { _executionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { TaskScheduler ts = TaskScheduler.Current; if (ts != TaskScheduler.Default) { _capturedContext = ts; } } // We need to set the continuation state before we swap in the delegate, so that // if there's a race between this and SetResult/Exception and SetResult/Exception // sees the _continuation as non-null, it'll be able to invoke it with the state // stored here. However, this also means that if this is used incorrectly (e.g. // 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?oldContinuation = _continuation; if (oldContinuation == null) { _continuationState = state; 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)) { //string stackInfo = new StackTrace(0, true).ToString(); //throw new InvalidOperationException("\r\nstatckinfo:\r\n" + stackInfo + "\r\n---------end----------\r\n"); return; } switch (_capturedContext) { case null: if (_executionContext != null) { #if !NETSTANDARD2_0 ThreadPool.QueueUserWorkItem(continuation, state, preferLocal: true); #else ThreadPool.QueueUserWorkItem(new WaitCallback(continuation), state); #endif } else { Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); } break; case TaskScheduler ts: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); break; } } }
void IValueTaskSource <T> .OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (Interlocked.Read(ref _wasFired) == 1) { continuation(state); return; } _continuation = continuation; _state = state; }
// This is called when someone awaits on the ValueTask, and tells us what method to call to complete. public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { if (token != _token) { ThrowMisuseException(); } UserToken = state; // Do the exchange so we know we're the only ones that could invoke the continuation. Action <object>?prevContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null); // Check whether we've already finished. if (ReferenceEquals(prevContinuation, _completedSentinel)) { // This means the operation has already completed; most likely because we completed before // we could attach the continuation. // Don't need to store the user token. UserToken = null; // We need to set forceAsync here and dispatch on the ThreadPool, otherwise // we can hit a stackoverflow! InvokeContinuation(continuation, state, forceAsync: true); } else if (prevContinuation != null) { throw new InvalidOperationException("Continuation being attached more than once."); } }
void IValueTaskSource <LockToken> .OnCompleted(Action <object> continuation, object state, short key, ValueTaskSourceOnCompletedFlags flags) { if (continuation == null) { return; } // set the state first, as we'll always *read* the continuation first, so we can't get confused var oldState = Interlocked.CompareExchange(ref _continuationsAndState[SlabSize + key], state, s_NoState); if (oldState != s_NoState) { ThrowMultipleContinuations(); } var oldContinuation = Interlocked.CompareExchange(ref _continuationsAndState[key], continuation, null); if (oldContinuation == s_Completed) { // we'd already finished; invoke it inline continuation.Invoke(state); } else if (oldContinuation != null) { ThrowMultipleContinuations(); } }
public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { var task = GetSource(); if (task.IsCompleted) { continuation(state); } else { OnCompletedSlow(task, continuation, state, flags); } }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { ValidateToken(token); _continuation = continuation; _state = state; _queue.ScheduleItemRequest(this._onItemGet); }
static async void OnCompletedSlow(ValueTask source, Action <object?> continuation, object?state, ValueTaskSourceOnCompletedFlags flags) { ExecutionContext? execContext = null; SynchronizationContext?syncContext = null; if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) == ValueTaskSourceOnCompletedFlags.FlowExecutionContext) { execContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) == ValueTaskSourceOnCompletedFlags.UseSchedulingContext) { syncContext = SynchronizationContext.Current; } try { await source.ConfigureAwait(false); } catch { } if (execContext != null) { ExecutionContext.Run(execContext, execContextCallback, Tuple.Create(continuation, state, syncContext)); } else if (syncContext != null) { syncContext.Post(syncContextCallback, Tuple.Create(continuation, state, syncContext)); } else { continuation(state); } }
// Handle continuations subscribed by awaiters void IValueTaskSource.OnCompleted(Action <object> continuation, object state, short _, ValueTaskSourceOnCompletedFlags flags) { var ctx = new ContinuationContext { Continuation = continuation, State = state }; CaptureThreadContext(ref ctx, flags); // Coordinate with concurrent SetCompleted() calls: // Increment the subscriptionsInProgress count and read the task state, in that order. Interlocked.Increment(ref _subscriptionsInProgress); if (_isTaskCompleted == 1) { // Task completed, execute the continuation immediately. Interlocked.Decrement(ref _subscriptionsInProgress); ExecuteContinuation(in ctx, isAsyncExecution: false); } else { // Enqueue the continuation for asynchronous execution. if (Interlocked.CompareExchange(ref _isFirstContinuationQueued, 1, 0) == 0) { // this is the first continuation, store directly to field. _firstContinuation = ctx; } else { // this is a secondary continuation, add to a heap allocated queue. var contQueue = GetOrCreateAdditionalContinuationQueue(); contQueue.Enqueue(ctx); } // signal that the continuation enqueue operation has completed Interlocked.Decrement(ref _subscriptionsInProgress); } }
public void OnCompleted(Action <Object> continuation, Object state, Int16 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) { var current = SynchronizationContext.Current; if (current != null && current.GetType() != typeof(SynchronizationContext)) { _capturedContext = current; } else { var current2 = TaskScheduler.Current; if (current2 != TaskScheduler.Default) { _capturedContext = current2; } } } Object?obj = _continuation; if (obj == null) { _continuationState = state; obj = Interlocked.CompareExchange(ref _continuation, continuation, null); } if (obj == null) { return; } #pragma warning disable 252,253 if (obj != ManualResetValueTaskSourceCoreShared.s_sentinel) #pragma warning restore 252,253 { throw new InvalidOperationException(); } var capturedContext = _capturedContext; if (capturedContext != null) { var synchronizationContext = capturedContext as SynchronizationContext; if (synchronizationContext == null) { var taskScheduler = capturedContext as TaskScheduler; if (taskScheduler != null) { Task.Factory.StartNew(continuation, state, CancellationToken.None, (TaskCreationOptions)8, taskScheduler); } } else { synchronizationContext.Post(delegate(Object s) { var tuple = (Tuple <Action <Object>, Object>)s; tuple.Item1(tuple.Item2); }, Tuple.Create(continuation, state)); } } else { Task.Factory.StartNew(continuation, state, CancellationToken.None, (TaskCreationOptions)8, TaskScheduler.Default); } }
void IValueTaskSource.OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _waitSource.OnCompleted(continuation, state, token, flags);
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { throw new NotImplementedException(); }
public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { UserToken = state; var prevContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null); if (ReferenceEquals(prevContinuation, _continuationCompleted)) { UserToken = null; ThreadPool.UnsafeQueueUserWorkItem(continuation, state, preferLocal: true); } }
public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) { if (_state != null) { ThrowMultipleContinuations(); } _state = state; var previousContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null); if (previousContinuation != null) { if (!ReferenceEquals(previousContinuation, CallbackCompleted)) { ThrowMultipleContinuations(); } new AsyncContinuation(continuation, state).Invoke(); } }
/// <summary>Schedules the continuation action for this box.</summary> public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) => _valueTaskSource.OnCompleted(continuation, state, token, flags);
void IValueTaskSource <FlushResult> .OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) => _responseCompleteTaskSource.OnCompleted(continuation, state, token, flags);
/// <summary>Schedules the continuation action for this operation.</summary> /// <param name="continuation">The continuation to invoke when the operation has completed.</param> /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param> /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param> /// <param name="flags">The flags describing the behavior of the continuation.</param> public void OnCompleted(Action <object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) // TODO-NULLABLE: https://github.com/dotnet/roslyn/issues/26761 { if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } ValidateToken(token); if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { _executionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { TaskScheduler ts = TaskScheduler.Current; if (ts != TaskScheduler.Default) { _capturedContext = ts; } } // We need to set the continuation state before we swap in the delegate, so that // if there's a race between this and SetResult/Exception and SetResult/Exception // sees the _continuation as non-null, it'll be able to invoke it with the state // stored here. However, this also means that if this is used incorrectly (e.g. // 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 oldContinuation = _continuation; if (oldContinuation == null) { _continuationState = state; 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)) { throw new InvalidOperationException(); } switch (_capturedContext) { case null: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); break; case TaskScheduler ts: Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts); break; } } }
// 如果被包装的 ValueTask 正在等待,那么底层状态机就会调用它 // 有两种发生的场景需要处理 // 1:如果操作还没完成,那么我们存储的延续任务continuation在操作一旦完成就会触发调用 // 2:如果操作已经完成,这种情况内部的continuation就应该已经设置成CallbackCompleted。如果是这样,那么只需调用延续任务即可 public void OnCompleted(Action <object?> continuation, object?state, short token, ValueTaskSourceOnCompletedFlags flags) { Console.WriteLine("." + token); if (token != this.token) { ThrowMultipleContinuations(); } if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0) { this.executionContext = ExecutionContext.Capture(); } if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0) { SynchronizationContext?sc = SynchronizationContext.Current; if (sc != null && sc.GetType() != typeof(SynchronizationContext)) { this.scheduler = sc; } else { TaskScheduler ts = TaskScheduler.Current; if (ts != TaskScheduler.Default) { this.scheduler = ts; } } } this.state = state; // continuation 必须要在操作完成后执行(如果没有完成,那么就要把continuation赋值为CallbackCompleted) var previousContinuation = Interlocked.CompareExchange(ref this.continuation, continuation, null); if (previousContinuation != null) { if (!ReferenceEquals(previousContinuation, CallbackCompleted)) { ThrowMultipleContinuations(); executionContext = null; this.state = null; InvokeContinuation(continuation, state, forceAsync: true); } } }