#if NET20 || NET30 || NET35 || !NET_4_6 using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Runtime.CompilerServices; namespace System.Threading.Tasks { public partial class Task { private const int _continuationsInitialization = 1; private const int _continuationsNotInitialized = 0; private const int _runningContinuations = 3; private const int _takingContinuations = 2; private List _continuations; private Thread _continuationsOwner; private int _continuationsStatus; /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// public Task ContinueWith(Action continuationAction) { return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Action continuationAction, CancellationToken cancellationToken) { return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// public Task ContinueWith(Action continuationAction, TaskScheduler scheduler) { return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// public Task ContinueWith(Action continuationAction, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// The that will be assigned to the new continuation task. /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Action continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// public Task ContinueWith(Action continuationAction, object state) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Action continuationAction, object state, CancellationToken cancellationToken) { return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// public Task ContinueWith(Action continuationAction, object state, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// public Task ContinueWith(Action continuationAction, object state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// The that will be assigned to the new continuation task. /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Action continuationAction, object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// public Task ContinueWith(Func continuationFunction) { return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Func continuationFunction, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// public Task ContinueWith(Func continuationFunction, TaskScheduler scheduler) { return ContinueWith(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// public Task ContinueWith(Func continuationFunction, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Func continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// public Task ContinueWith(Func continuationFunction, object state) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Func continuationFunction, object state, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// public Task ContinueWith(Func continuationFunction, object state, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// public Task ContinueWith(Func continuationFunction, object state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// public Task ContinueWith(Func continuationFunction, object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, cancellationToken, continuationOptions); } /// /// Converts TaskContinuationOptions to TaskCreationOptions, and also does /// some validity checking along the way. /// /// Incoming TaskContinuationOptions /// Outgoing TaskCreationOptions /// Outgoing InternalTaskOptions internal static void CreationOptionsFromContinuationOptions(TaskContinuationOptions continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions) { // This is used a couple of times below const TaskContinuationOptions NotOnAnything = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.NotOnRanToCompletion; const TaskContinuationOptions CreationOptionsMask = TaskContinuationOptions.PreferFairness | TaskContinuationOptions.LongRunning | TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.HideScheduler | TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.RunContinuationsAsynchronously; // Check that LongRunning and ExecuteSynchronously are not specified together const TaskContinuationOptions IllegalMask = TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.LongRunning; if ((continuationOptions & IllegalMask) == IllegalMask) { throw new ArgumentOutOfRangeException("continuationOptions", "The specified TaskContinuationOptions combined LongRunning and ExecuteSynchronously. Synchronous continuations should not be long running."); } // Check that no illegal options were specified if ((continuationOptions & ~(CreationOptionsMask | NotOnAnything | TaskContinuationOptions.LazyCancellation | TaskContinuationOptions.ExecuteSynchronously)) != 0) { throw new ArgumentOutOfRangeException("continuationOptions"); } // Check that we didn't specify "not on anything" if ((continuationOptions & NotOnAnything) == NotOnAnything) { throw new ArgumentOutOfRangeException("continuationOptions", "The specified TaskContinuationOptions excluded all continuation kinds."); } // This passes over all but LazyCancellation, which has no representation in TaskCreationOptions creationOptions = (TaskCreationOptions)(continuationOptions & CreationOptionsMask); // internalOptions has at least ContinuationTask ... internalOptions = InternalTaskOptions.ContinuationTask; // ... and possibly LazyCancellation if ((continuationOptions & TaskContinuationOptions.LazyCancellation) != 0) { internalOptions |= InternalTaskOptions.LazyCancellation; } } internal void ContinueWithCore(Task continuationTask, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions options) { Contract.Requires(continuationTask != null, "Task.ContinueWithCore(): null continuationTask"); Contract.Requires(scheduler != null, "Task.ContinueWithCore(): null scheduler"); Contract.Requires(!continuationTask.IsCompleted, "Did not expect continuationTask to be completed"); // Create a TaskContinuation TaskContinuation continuation = new StandardTaskContinuation(continuationTask, options, scheduler); // If cancellationToken is cancellable, then assign it. if (cancellationToken.CanBeCanceled) { if (IsCompleted || cancellationToken.IsCancellationRequested) { // If the antecedent has completed, then we will not be queuing up // the continuation in the antecedent's continuation list. Likewise, // if the cancellationToken has been canceled, continuationTask will // be completed in the AssignCancellationToken call below, and there // is no need to queue the continuation to the antecedent's continuation // list. In either of these two cases, we will pass "null" for the antecedent, // meaning "the cancellation callback should not attempt to remove the // continuation from its antecedent's continuation list". continuationTask.AssignCancellationToken(cancellationToken, null, null); } else { // The antecedent is not yet complete, so there is a pretty good chance // that the continuation will be queued up in the antecedent. Assign the // cancellation token with information about the antecedent, so that the // continuation can be dequeued upon the signalling of the token. // // It's possible that the antecedent completes before the call to AddTaskContinuation, // and that is a benign ----. It just means that the cancellation will result in // a futile search of the antecedent's continuation list. continuationTask.AssignCancellationToken(cancellationToken, this, continuation); } } // In the case of a pre-canceled token, continuationTask will have been completed // in a Canceled state by now. If such is the case, there is no need to go through // the motions of queuing up the continuation for eventual execution. if (!continuationTask.IsCompleted) { // Attempt to enqueue the continuation var continuationQueued = AddTaskContinuation(continuation, /*addBeforeOthers:*/ false); // If the continuation was not queued (because the task completed), then run it now. if (!continuationQueued) { continuation.Run(this, true); } } } /// /// Runs all of the continuations, as appropriate. /// internal void FinishContinuations() { if (Interlocked.CompareExchange(ref _continuationsStatus, _takingContinuations, _continuationsNotInitialized) == _continuationsNotInitialized) { return; } if (Interlocked.CompareExchange(ref _continuationsStatus, _takingContinuations, _continuationsInitialization) == _continuationsInitialization) { var continuations = Interlocked.CompareExchange(ref _continuations, null, null); if (continuations == null) { return; } // Wait for any concurrent adds or removes to be retired try { var spinWait = new SpinWait(); LockEnter(spinWait); Interlocked.CompareExchange(ref _continuations, null, continuations); Thread.VolatileWrite(ref _continuationsStatus, _runningContinuations); } finally { LockExit(); } // Skip synchronous execution of continuations if this task's thread was aborted var canInlineContinuations = Thread.VolatileRead(ref _threadAbortedmanaged) == 0 && (Thread.CurrentThread.ThreadState != ThreadState.AbortRequested) && ((_creationOptions & TaskCreationOptions.RunContinuationsAsynchronously) == 0); // // Begin processing of continuation list // var continuationCount = continuations.Count; // Fire the asynchronous continuations first ... for (var index = 0; index < continuationCount; index++) { // Synchronous continuation tasks will have the ExecuteSynchronously option, // and we're looking for asynchronous tasks... var tc = continuations[index] as StandardTaskContinuation; if (tc == null || (tc.Options & TaskContinuationOptions.ExecuteSynchronously) != 0) { continue; } continuations[index] = null; // so that we can skip this later tc.Run(this, canInlineContinuations); } // ... and then fire the synchronous continuations (if there are any). // This includes ITaskCompletionAction, AwaitTaskContinuations, and // Action delegates, which are all by default implicitly synchronous. for (var index = 0; index < continuationCount; index++) { var currentContinuation = continuations[index]; if (currentContinuation == null) { continue; } continuations[index] = null; // to enable free'ing up memory earlier // If the continuation is an Action delegate, it came from an await continuation, // and we should use AwaitTaskContinuation to run it. var ad = currentContinuation as Action; if (ad != null) { AwaitTaskContinuation.RunOrScheduleAction(ad, canInlineContinuations, ref InternalCurrent); } else { // If it's a TaskContinuation object of some kind, invoke it. var tc = currentContinuation as TaskContinuation; if (tc != null) { // We know that this is a synchronous continuation because the // asynchronous ones have been weeded out tc.Run(this, canInlineContinuations); } // Otherwise, it must be an ITaskCompletionAction, so invoke it. else { Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction"); var action = (ITaskCompletionAction)currentContinuation; action.Invoke(this); } } } } } internal void RemoveContinuation(object continuationObject) // could be TaskContinuation or Action { try { var continuations = GetContinuations(); if (continuations == null || Status == TaskStatus.RanToCompletion) { return; } var index = continuations.IndexOf(continuationObject); if (index != -1) { continuations[index] = null; } } finally { LockExit(); } } // Record a continuation task or action. // Return true if and only if we successfully queued a continuation. private bool AddTaskContinuation(object continuationObject, bool addBeforeOthers) { Contract.Requires(continuationObject != null); try { var continuations = RetrieveContinuations(); if (continuations == null || Status == TaskStatus.RanToCompletion) { return false; } if (addBeforeOthers) { continuations.Insert(0, continuationObject); } else { continuations.Add(continuationObject); } return true; } finally { LockExit(); } } // Same as the above overload, just with a stack mark parameter. private Task ContinueWith(Action continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null action if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } // Throw on continuation with null TaskScheduler if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask ( this, continuationAction, null, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } // Same as the above overload, just with a stack mark parameter. private Task ContinueWith(Action continuationAction, object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null action if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } // Throw on continuation with null TaskScheduler if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationTaskFromTask ( this, continuationAction, state, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } // Same as the above overload, just with a stack mark parameter. private Task ContinueWith(Func continuationFunction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null function if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } // Throw on continuation with null task scheduler if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask ( this, continuationFunction, null, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } // Same as the above overload, just with a stack mark parameter. private Task ContinueWith(Func continuationFunction, object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { // Throw on continuation with null function if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } // Throw on continuation with null task scheduler if (scheduler == null) { throw new ArgumentNullException("scheduler"); } Contract.EndContractBlock(); TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); Task continuationTask = new ContinuationResultTaskFromTask ( this, continuationFunction, state, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } private List GetContinuations() { if (IsCompleted) { return null; } if (Thread.VolatileRead(ref _continuationsStatus) == _continuationsInitialization) { // Initializing or initilized var spinWait = new SpinWait(); List continuations; while ((continuations = Interlocked.CompareExchange(ref _continuations, null, null)) == null) { spinWait.SpinOnce(); } LockEnter(spinWait); if (Thread.VolatileRead(ref _continuationsStatus) == _continuationsInitialization) { return continuations; } // It is being taken or has already been taken for execution return null; } return null; } private void LockEnter(SpinWait spinWait) { while (true) { if (Interlocked.CompareExchange(ref _continuations, null, null) == null) { return; } var thread = Interlocked.CompareExchange(ref _continuationsOwner, Thread.CurrentThread, null); if (thread == null) { return; } spinWait.SpinOnce(); } } private void LockExit() { Interlocked.CompareExchange(ref _continuationsOwner, null, Thread.CurrentThread); } private List RetrieveContinuations() { if (IsCompleted) { return null; } List continuations = null; var found = Thread.VolatileRead(ref _continuationsStatus); var spinWait = new SpinWait(); switch (found) { case _continuationsNotInitialized: // Not initialized if (Interlocked.CompareExchange(ref _continuationsStatus, _continuationsInitialization, _continuationsNotInitialized) == _continuationsNotInitialized) { var created = new List(); continuations = Interlocked.CompareExchange(ref _continuations, created, null); if (continuations == null) { continuations = created; } goto default; } goto case _continuationsInitialization; case _continuationsInitialization: // Initializing or initilized while (Thread.VolatileRead(ref _continuationsStatus) == _continuationsInitialization && (continuations = Interlocked.CompareExchange(ref _continuations, null, null)) == null) { spinWait.SpinOnce(); } if (Thread.VolatileRead(ref _continuationsStatus) == _takingContinuations) { return null; } goto default; case _takingContinuations: case _runningContinuations: // Being taken for execution, or // Already taken for execution return null; default: // The continuations may have already executed at this point LockEnter(spinWait); if (Thread.VolatileRead(ref _continuationsStatus) == _continuationsInitialization) { return continuations; } // It is being taken or has already been taken for execution return null; } } } public partial class Task { /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImpl(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction) { return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken) { return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, TaskScheduler scheduler) { return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, object> continuationAction, object state) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// The that will be assigned to the new continuation task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, object> continuationAction, object state, CancellationToken cancellationToken) { return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, object> continuationAction, object state, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the continuation criteria specified through the parameter are not met, the continuation task will be canceled /// instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, object> continuationAction, object state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// An action to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation action. /// The that will be assigned to the new continuation task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed. If the criteria specified through the parameter /// are not met, the continuation task will be canceled instead of scheduled. /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Action, object> continuationAction, object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction) { return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// The that will be assigned to the new task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler) { return ContinueWith(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task as an argument. /// /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . This task's completion state will be transferred to the task returned /// from the ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be passed as /// an argument this completed task. /// /// The that will be assigned to the new task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . /// This task's completion state will be transferred to the task returned from the /// ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, TNewResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, scheduler, cancellationToken, continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new task. /// A new continuation . /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, CancellationToken cancellationToken) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// The to associate with the continuation task and to use for its execution. /// /// A new continuation . /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The argument is null. /// /// /// The argument is null. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current /// task has completed, whether it completes due to running to completion successfully, faulting due /// to an unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . This task's completion state will be transferred to the task returned /// from the ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, TaskContinuationOptions continuationOptions) { return ContinueWith(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions); } /// /// Creates a continuation that executes when the target completes. /// /// /// The type of the result produced by the continuation. /// /// /// A function to run when the completes. When run, the delegate will be /// passed the completed task and the caller-supplied state object as arguments. /// /// An object representing data to be used by the continuation function. /// The that will be assigned to the new task. /// /// Options for when the continuation is scheduled and how it behaves. This includes criteria, such /// as OnlyOnCanceled, as /// well as execution options, such as ExecuteSynchronously. /// /// /// The to associate with the continuation task and to use for its /// execution. /// /// A new continuation . /// /// /// The returned will not be scheduled for execution until the current task has /// completed, whether it completes due to running to completion successfully, faulting due to an /// unhandled exception, or exiting out early due to being canceled. /// /// /// The , when executed, should return a . /// This task's completion state will be transferred to the task returned from the /// ContinueWith call. /// /// /// /// The argument is null. /// /// /// The argument specifies an invalid value for TaskContinuationOptions. /// /// /// The argument is null. /// /// The provided CancellationToken /// has already been disposed. /// [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable public Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { return ContinueWith(continuationFunction, state, scheduler, cancellationToken, continuationOptions); } // Same as the above overload, only with a stack mark. internal Task ContinueWith(Action> continuationAction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions ( continuationOptions, out creationOptions, out internalOptions ); Task continuationTask = new ContinuationTaskFromResultTask ( this, continuationAction, null, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } // Same as the above overload, only with a stack mark. internal Task ContinueWith(Action, object> continuationAction, object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationAction == null) { throw new ArgumentNullException("continuationAction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions ( continuationOptions, out creationOptions, out internalOptions ); Task continuationTask = new ContinuationTaskFromResultTask ( this, continuationAction, state, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationTask, scheduler, cancellationToken, continuationOptions); return continuationTask; } // Same as the above overload, just with a stack mark. internal Task ContinueWith(Func, TNewResult> continuationFunction, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, null, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); return continuationFuture; } // Same as the above overload, just with a stack mark. internal Task ContinueWith(Func, object, TNewResult> continuationFunction, object state, TaskScheduler scheduler, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions) { if (continuationFunction == null) { throw new ArgumentNullException("continuationFunction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } TaskCreationOptions creationOptions; InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, out creationOptions, out internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, state, creationOptions, internalOptions ); // Register the continuation. If synchronous execution is requested, this may // actually invoke the continuation before returning. ContinueWithCore(continuationFuture, scheduler, cancellationToken, continuationOptions); return continuationFuture; } } } #endif