summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Threading/Tasks/Task.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Threading/Tasks/Task.cs')
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs716
1 files changed, 82 insertions, 634 deletions
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index cf081f75fd..7013c5c5e0 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -18,7 +18,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;
using System.Security;
-using System.Security.Permissions;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.Contracts;
@@ -147,7 +146,6 @@ namespace System.Threading.Tasks
private static StackGuard t_stackGuard; // The stack guard object for this thread
internal static int s_taskIdCounter; //static counter used to generate unique task IDs
- private readonly static TaskFactory s_factory = new TaskFactory();
private volatile int m_taskId; // this task's unique ID. initialized only if it is ever requested
@@ -365,12 +363,9 @@ namespace System.Threading.Tasks
/// </summary>
/// <param name="action">The delegate that represents the code to execute in the Task.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="action"/> argument is null.</exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action)
: this(action, null, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -383,12 +378,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, CancellationToken cancellationToken)
: this(action, null, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -406,12 +398,9 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, TaskCreationOptions creationOptions)
: this(action, null, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -433,12 +422,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(action, null, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
@@ -450,12 +436,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="action"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state)
: this(action, state, null, default(CancellationToken), TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -470,12 +453,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, CancellationToken cancellationToken)
: this(action, state, null, cancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -494,12 +474,9 @@ namespace System.Threading.Tasks
/// The <paramref name="creationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskCreationOptions"/>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, TaskCreationOptions creationOptions)
: this(action, state, Task.InternalCurrentIfAttached(creationOptions), default(CancellationToken), creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -522,19 +499,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task(Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
: this(action, state, Task.InternalCurrentIfAttached(creationOptions), cancellationToken, creationOptions, InternalTaskOptions.None, null)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
- }
-
- internal Task(Action<object> action, object state, Task parent, CancellationToken cancellationToken,
- TaskCreationOptions creationOptions, InternalTaskOptions internalOptions, TaskScheduler scheduler, ref StackCrawlMark stackMark)
- : this(action, state, parent, cancellationToken, creationOptions, internalOptions, scheduler)
- {
- PossiblyCaptureContext(ref stackMark);
}
/// <summary>
@@ -557,10 +524,8 @@ namespace System.Threading.Tasks
}
Contract.EndContractBlock();
- // Keep a link to your parent if: (A) You are attached, or (B) you are self-replicating.
- if (parent != null &&
- ((creationOptions & TaskCreationOptions.AttachedToParent) != 0 ||
- (internalOptions & InternalTaskOptions.SelfReplicating) != 0))
+ // Keep a link to the parent if attached
+ if (parent != null && (creationOptions & TaskCreationOptions.AttachedToParent) != 0)
{
EnsureContingentPropertiesInitializedUnsafe().m_parent = parent;
}
@@ -586,6 +551,10 @@ namespace System.Threading.Tasks
m_stateObject = state;
m_taskScheduler = scheduler;
+ Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null,
+ "Captured an ExecutionContext when one was already captured.");
+ CapturedContext = ExecutionContext.Capture();
+
// Check for validity of options
if ((creationOptions &
~(TaskCreationOptions.AttachedToParent |
@@ -602,22 +571,13 @@ namespace System.Threading.Tasks
// Check the validity of internalOptions
int illegalInternalOptions =
(int) (internalOptions &
- ~(InternalTaskOptions.SelfReplicating |
- InternalTaskOptions.ChildReplica |
- InternalTaskOptions.PromiseTask |
+ ~(InternalTaskOptions.PromiseTask |
InternalTaskOptions.ContinuationTask |
InternalTaskOptions.LazyCancellation |
InternalTaskOptions.QueuedByRuntime));
Debug.Assert(illegalInternalOptions == 0, "TaskConstructorCore: Illegal internal options");
#endif
- // Throw exception if the user specifies both LongRunning and SelfReplicating
- if (((creationOptions & TaskCreationOptions.LongRunning) != 0) &&
- ((internalOptions & InternalTaskOptions.SelfReplicating) != 0))
- {
- ThrowHelper.ThrowInvalidOperationException(ExceptionResource.Task_ctor_LRandSR);
- }
-
// Assign options to m_stateAndOptionsFlag.
Debug.Assert(m_stateFlags == 0, "TaskConstructorCore: non-zero m_stateFlags");
Debug.Assert((((int)creationOptions) | OptionsMask) == OptionsMask, "TaskConstructorCore: options take too many bits");
@@ -648,9 +608,7 @@ namespace System.Threading.Tasks
// we need to do this as the very last thing in the construction path, because the CT registration could modify m_stateFlags
if (cancellationToken.CanBeCanceled)
{
- Debug.Assert((internalOptions &
- (InternalTaskOptions.ChildReplica | InternalTaskOptions.SelfReplicating | InternalTaskOptions.ContinuationTask)) == 0,
- "TaskConstructorCore: Did not expect to see cancelable token for replica/replicating or continuation task.");
+ Debug.Assert((internalOptions & InternalTaskOptions.ContinuationTask) == 0, "TaskConstructorCore: Did not expect to see cancelable token for continuation task.");
AssignCancellationToken(cancellationToken, null, null);
}
@@ -757,24 +715,6 @@ namespace System.Threading.Tasks
}
}
-
- /// <summary>
- /// Captures the ExecutionContext so long as flow isn't suppressed.
- /// </summary>
- /// <param name="stackMark">A stack crawl mark pointing to the frame of the caller.</param>
-
- internal void PossiblyCaptureContext(ref StackCrawlMark stackMark)
- {
- Debug.Assert(m_contingentProperties == null || m_contingentProperties.m_capturedContext == null,
- "Captured an ExecutionContext when one was already captured.");
-
- // In the legacy .NET 3.5 build, we don't have the optimized overload of Capture()
- // available, so we call the parameterless overload.
- CapturedContext = ExecutionContext.Capture(
- ref stackMark,
- ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
- }
-
// Internal property to process TaskCreationOptions access and mutation.
internal TaskCreationOptions Options
{
@@ -989,16 +929,14 @@ namespace System.Threading.Tasks
/// </summary>
internal void AddNewChild()
{
- Debug.Assert(Task.InternalCurrent == this || this.IsSelfReplicatingRoot, "Task.AddNewChild(): Called from an external context");
+ Debug.Assert(Task.InternalCurrent == this, "Task.AddNewChild(): Called from an external context");
var props = EnsureContingentPropertiesInitialized();
- if (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot)
+ if (props.m_completionCountdown == 1)
{
// A count of 1 indicates so far there was only the parent, and this is the first child task
// Single kid => no fuss about who else is accessing the count. Let's save ourselves 100 cycles
- // We exclude self replicating root tasks from this optimization, because further child creation can take place on
- // other cores and with bad enough timing this write may not be visible to them.
props.m_completionCountdown++;
}
else
@@ -1264,7 +1202,7 @@ namespace System.Threading.Tasks
// Implicitly converts action to object and handles the meat of the StartNew() logic.
internal static Task InternalStartNew(
Task creatingTask, Delegate action, object state, CancellationToken cancellationToken, TaskScheduler scheduler,
- TaskCreationOptions options, InternalTaskOptions internalOptions, ref StackCrawlMark stackMark)
+ TaskCreationOptions options, InternalTaskOptions internalOptions)
{
// Validate arguments.
if (scheduler == null)
@@ -1276,7 +1214,6 @@ namespace System.Threading.Tasks
// Create and schedule the task. This throws an InvalidOperationException if already shut down.
// Here we add the InternalTaskOptions.QueuedByRuntime to the internalOptions, so that TaskConstructorCore can skip the cancellation token registration
Task t = new Task(action, state, creatingTask, cancellationToken, options, internalOptions | InternalTaskOptions.QueuedByRuntime, scheduler);
- t.PossiblyCaptureContext(ref stackMark);
t.ScheduleAndStart(false);
return t;
@@ -1615,23 +1552,10 @@ namespace System.Threading.Tasks
/// of <see cref="System.Threading.Tasks.TaskFactory"/>, as would result from using
/// the default constructor on TaskFactory.
/// </remarks>
- public static TaskFactory Factory { get { return s_factory; } }
-
- /// <summary>A task that's already been completed successfully.</summary>
- private static Task s_completedTask;
+ public static TaskFactory Factory { get; } = new TaskFactory();
/// <summary>Gets a task that's already been completed successfully.</summary>
- /// <remarks>May not always return the same instance.</remarks>
- public static Task CompletedTask
- {
- get
- {
- var completedTask = s_completedTask;
- if (completedTask == null)
- s_completedTask = completedTask = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken)); // benign initialization race condition
- return completedTask;
- }
- }
+ public static Task CompletedTask { get; } = new Task(false, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
/// <summary>
/// Provides an event that can be used to wait for completion.
@@ -1663,35 +1587,6 @@ namespace System.Threading.Tasks
}
}
- /// <summary>
- /// Determines whether this is the root task of a self replicating group.
- /// </summary>
- internal bool IsSelfReplicatingRoot
- {
- get
- {
- // Return true if self-replicating bit is set and child replica bit is not set
- return (Options & (TaskCreationOptions)(InternalTaskOptions.SelfReplicating | InternalTaskOptions.ChildReplica))
- == (TaskCreationOptions)InternalTaskOptions.SelfReplicating;
- }
- }
-
- /// <summary>
- /// Determines whether the task is a replica itself.
- /// </summary>
- internal bool IsChildReplica
- {
- get { return (Options & (TaskCreationOptions)InternalTaskOptions.ChildReplica) != 0; }
- }
-
- internal int ActiveChildCount
- {
- get
- {
- var props = Volatile.Read(ref m_contingentProperties);
- return props != null ? props.m_completionCountdown - 1 : 0;
- }
- }
/// <summary>
/// The property formerly known as IsFaulted.
@@ -1737,7 +1632,7 @@ namespace System.Threading.Tasks
}
else
{
- return m_contingentProperties?.m_capturedContext ?? ExecutionContext.PreAllocatedDefault;
+ return m_contingentProperties?.m_capturedContext ?? ExecutionContext.Default;
}
}
set
@@ -1747,7 +1642,7 @@ namespace System.Threading.Tasks
{
m_stateFlags |= TASK_STATE_EXECUTIONCONTEXT_IS_NULL;
}
- else if (!value.IsPreAllocatedDefault) // not the default context, then inflate the contingent properties and set it
+ else if (value != ExecutionContext.Default) // not the default context, then inflate the contingent properties and set it
{
EnsureContingentPropertiesInitializedUnsafe().m_capturedContext = value;
}
@@ -1755,32 +1650,6 @@ namespace System.Threading.Tasks
}
}
- /// <summary>
- /// Static helper function to copy specific ExecutionContext
- /// </summary>
- /// <param name="capturedContext">The captured context</param>
- /// <returns>The copied context, null if the capturedContext is null</returns>
- private static ExecutionContext CopyExecutionContext(ExecutionContext capturedContext)
- {
- if (capturedContext == null)
- return null;
- if (capturedContext.IsPreAllocatedDefault)
- return ExecutionContext.PreAllocatedDefault;
-
- return capturedContext.CreateCopy();
- }
-
-
-#if DEBUG
- /// <summary>
- /// Retrieves an identifier for the task.
- /// </summary>
- internal int InternalId
- {
- get { return GetHashCode(); }
- }
-#endif
-
/////////////
// methods
@@ -1920,7 +1789,7 @@ namespace System.Threading.Tasks
catch (ThreadAbortException tae)
{
AddException(tae);
- FinishThreadAbortedTask(true, false);
+ FinishThreadAbortedTask(delegateRan:false);
}
catch (Exception e)
{
@@ -1930,10 +1799,10 @@ namespace System.Threading.Tasks
AddException(tse);
Finish(false);
- // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew()
- // or from the self replicating logic, because in both cases the exception is either propagated outside directly, or added
- // to an enclosing parent. However we won't do this for continuation tasks, because in that case we internally eat the exception
- // and therefore we need to make sure the user does later observe it explicitly or see it on the finalizer.
+ // Now we need to mark ourselves as "handled" to avoid crashing the finalizer thread if we are called from StartNew(),
+ // because the exception is either propagated outside directly, or added to an enclosing parent. However we won't do this for
+ // continuation tasks, because in that case we internally eat the exception and therefore we need to make sure the user does
+ // later observe it explicitly or see it on the finalizer.
if ((Options & (TaskCreationOptions)InternalTaskOptions.ContinuationTask) == 0)
{
@@ -2192,11 +2061,9 @@ namespace System.Threading.Tasks
var props = Volatile.Read(ref m_contingentProperties);
if (props == null || // no contingent properties means no children, so it's safe to complete ourselves
- (props.m_completionCountdown == 1 && !IsSelfReplicatingRoot) ||
+ (props.m_completionCountdown == 1) ||
// Count of 1 => either all children finished, or there were none. Safe to complete ourselves
// without paying the price of an Interlocked.Decrement.
- // However we need to exclude self replicating root tasks from this optimization, because
- // they can have children joining in, or finishing even after the root task delegate is done.
Interlocked.Decrement(ref props.m_completionCountdown) == 0) // Reaching this sub clause means there may be remaining active children,
// and we could be racing with one of them to call FinishStageTwo().
// So whoever does the final Interlocked.Dec is responsible to finish.
@@ -2424,19 +2291,13 @@ namespace System.Threading.Tasks
/// This makes a note in the state flags so that we avoid any costly synchronous operations in the finish codepath
/// such as inlined continuations
/// </summary>
- /// <param name="bTAEAddedToExceptionHolder">
- /// Indicates whether the ThreadAbortException was added to this task's exception holder.
- /// This should always be true except for the case of non-root self replicating task copies.
- /// </param>
/// <param name="delegateRan">Whether the delegate was executed.</param>
- internal void FinishThreadAbortedTask(bool bTAEAddedToExceptionHolder, bool delegateRan)
+ internal void FinishThreadAbortedTask(bool delegateRan)
{
- Debug.Assert(!bTAEAddedToExceptionHolder || m_contingentProperties?.m_exceptionsHolder != null,
- "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized");
+ Debug.Assert(m_contingentProperties?.m_exceptionsHolder != null,
+ "FinishThreadAbortedTask() called on a task whose exception holder wasn't initialized");
- // this will only be false for non-root self replicating task copies, because all of their exceptions go to the root task.
- if (bTAEAddedToExceptionHolder)
- m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
+ m_contingentProperties.m_exceptionsHolder.MarkAsHandled(false);
// If this method has already been called for this task, or if this task has already completed, then
// return before actually calling Finish().
@@ -2447,220 +2308,33 @@ namespace System.Threading.Tasks
}
Finish(delegateRan);
-
}
/// <summary>
- /// Executes the task. This method will only be called once, and handles bookeeping associated with
- /// self-replicating tasks, in addition to performing necessary exception marshaling.
+ /// Executes the task. This method will only be called once, and handles any necessary exception marshaling.
/// </summary>
private void Execute()
{
- if (IsSelfReplicatingRoot)
+ try
{
- ExecuteSelfReplicating(this);
+ InnerInvoke();
}
- else
+ catch (ThreadAbortException tae)
{
- try
- {
- InnerInvoke();
- }
- catch (ThreadAbortException tae)
- {
- // Don't record the TAE or call FinishThreadAbortedTask for a child replica task --
- // it's already been done downstream.
- if (!IsChildReplica)
- {
- // Record this exception in the task's exception list
- HandleException(tae);
+ // Record this exception in the task's exception list
+ HandleException(tae);
- // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to
- // skip the regular Finish codepath. In order not to leave the task unfinished, we now call
- // FinishThreadAbortedTask here.
- FinishThreadAbortedTask(true, true);
- }
- }
- catch (Exception exn)
- {
- // Record this exception in the task's exception list
- HandleException(exn);
- }
+ // This is a ThreadAbortException and it will be rethrown from this catch clause, causing us to
+ // skip the regular Finish codepath. In order not to leave the task unfinished, we now call
+ // FinishThreadAbortedTask here.
+ FinishThreadAbortedTask(delegateRan: true);
}
- }
-
- // Allows (internal) deriving classes to support limited replication.
- // (By default, replication is basically unlimited).
- internal virtual bool ShouldReplicate()
- {
- return true;
- }
-
- // Allows (internal) deriving classes to instantiate the task replica as a Task super class of their choice
- // (By default, we create a regular Task instance)
- internal virtual Task CreateReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica)
- {
- return new Task(taskReplicaDelegate, stateObject, parentTask, default(CancellationToken),
- creationOptionsForReplica, internalOptionsForReplica, parentTask.ExecutingTaskScheduler);
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal virtual Object SavedStateForNextReplica
- {
- get { return null; }
-
- set { /*do nothing*/ }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal virtual Object SavedStateFromPreviousReplica
- {
- get { return null; }
-
- set { /*do nothing*/ }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to hand over the child replica that they
- // had queued, so that the replacement replica can work with that child task instead of queuing up yet another one
- internal virtual Task HandedOverChildReplica
- {
- get { return null; }
-
- set { /* do nothing*/ }
- }
-
- private static void ExecuteSelfReplicating(Task root)
- {
- TaskCreationOptions creationOptionsForReplicas = root.CreationOptions | TaskCreationOptions.AttachedToParent;
- InternalTaskOptions internalOptionsForReplicas =
- InternalTaskOptions.ChildReplica | // child replica flag disables self replication for the replicas themselves.
- InternalTaskOptions.SelfReplicating | // we still want to identify this as part of a self replicating group
- InternalTaskOptions.QueuedByRuntime; // we queue and cancel these tasks internally, so don't allow CT registration to take place
-
-
- // Important Note: The child replicas we launch from here will be attached the root replica (by virtue of the root.CreateReplicaTask call)
- // because we need the root task to receive all their exceptions, and to block until all of them return
-
-
- // This variable is captured in a closure and shared among all replicas.
- bool replicasAreQuitting = false;
-
- // Set up a delegate that will form the body of the root and all recursively created replicas.
- Action<object> taskReplicaDelegate = null;
- taskReplicaDelegate = delegate
+ catch (Exception exn)
{
- Task currentTask = Task.InternalCurrent;
-
-
- // Check if a child task has been handed over by a prematurely quiting replica that we might be a replacement for.
- Task childTask = currentTask.HandedOverChildReplica;
-
- if (childTask == null)
- {
- // Apparently we are not a replacement task. This means we need to queue up a child task for replication to progress
-
- // Down-counts a counter in the root task.
- if (!root.ShouldReplicate()) return;
-
- // If any of the replicas have quit, we will do so ourselves.
- if (Volatile.Read(ref replicasAreQuitting))
- {
- return;
- }
-
- // Propagate a copy of the context from the root task. It may be null if flow was suppressed.
- ExecutionContext creatorContext = root.CapturedContext;
-
-
- childTask = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler,
- creationOptionsForReplicas, internalOptionsForReplicas);
-
- childTask.CapturedContext = CopyExecutionContext(creatorContext);
-
- childTask.ScheduleAndStart(false);
- }
-
-
-
- // Finally invoke the meat of the task.
- // Note that we are directly calling root.InnerInvoke() even though we are currently be in the action delegate of a child replica
- // This is because the actual work was passed down in that delegate, and the action delegate of the child replica simply contains this
- // replication control logic.
- try
- {
- // passing in currentTask only so that the parallel debugger can find it
- root.InnerInvokeWithArg(currentTask);
- }
- catch (Exception exn)
- {
- // Record this exception in the root task's exception list
- root.HandleException(exn);
-
- if (exn is ThreadAbortException)
- {
- // If this is a ThreadAbortException it will escape this catch clause, causing us to skip the regular Finish codepath
- // In order not to leave the task unfinished, we now call FinishThreadAbortedTask here
- currentTask.FinishThreadAbortedTask(false, true);
- }
- }
-
- Object savedState = currentTask.SavedStateForNextReplica;
-
- // check for premature exit
- if (savedState != null)
- {
- // the replica decided to exit early
- // we need to queue up a replacement, attach the saved state, and yield the thread right away
-
- Task replacementReplica = root.CreateReplicaTask(taskReplicaDelegate, root.m_stateObject, root, root.ExecutingTaskScheduler,
- creationOptionsForReplicas, internalOptionsForReplicas);
-
- // Propagate a copy of the context from the root task to the replacement task
- ExecutionContext creatorContext = root.CapturedContext;
- replacementReplica.CapturedContext = CopyExecutionContext(creatorContext);
-
- replacementReplica.HandedOverChildReplica = childTask;
- replacementReplica.SavedStateFromPreviousReplica = savedState;
-
- replacementReplica.ScheduleAndStart(false);
- }
- else
- {
- // The replica finished normally, which means it can't find more work to grab.
- // Time to mark replicas quitting
-
- replicasAreQuitting = true;
-
- // InternalCancel() could conceivably throw in the underlying scheduler's TryDequeue() method.
- // If it does, then make sure that we record it.
- try
- {
- childTask.InternalCancel(true);
- }
- catch (Exception e)
- {
- // Apparently TryDequeue threw an exception. Before propagating that exception, InternalCancel should have
- // attempted an atomic state transition and a call to CancellationCleanupLogic() on this task. So we know
- // the task was properly cleaned up if it was possible.
- //
- // Now all we need to do is to Record the exception in the root task.
-
- root.HandleException(e);
- }
-
- // No specific action needed if the child could not be canceled
- // because we attached it to the root task, which should therefore be receiving any exceptions from the child,
- // and root.wait will not return before this child finishes anyway.
-
- }
- };
-
- //
- // Now we execute as the root task
- //
- taskReplicaDelegate(null);
+ // Record this exception in the task's exception list
+ HandleException(exn);
+ }
}
/// <summary>
@@ -2683,7 +2357,7 @@ namespace System.Threading.Tasks
if (!IsCompleted)
{
HandleException(tae);
- FinishThreadAbortedTask(true, false);
+ FinishThreadAbortedTask(delegateRan:false);
}
}
@@ -2693,10 +2367,10 @@ namespace System.Threading.Tasks
///
/// </summary>
/// <param name="bPreventDoubleExecution"> Performs atomic updates to prevent double execution. Should only be set to true
- /// in codepaths servicing user provided TaskSchedulers. The ConcRT or ThreadPool schedulers don't need this. </param>
+ /// in codepaths servicing user provided TaskSchedulers. The ThreadPool scheduler doesn't need this. </param>
internal bool ExecuteEntry(bool bPreventDoubleExecution)
{
- if (bPreventDoubleExecution || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0))
+ if (bPreventDoubleExecution)
{
int previousState = 0;
@@ -2772,18 +2446,10 @@ namespace System.Threading.Tasks
}
else
{
- if (IsSelfReplicatingRoot || IsChildReplica)
- {
- CapturedContext = CopyExecutionContext(ec);
- }
-
// Run the task. We need a simple shim that converts the
// object back into a Task object, so that we can Execute it.
- // Lazily initialize the callback delegate; benign race condition
- var callback = s_ecCallback;
- if (callback == null) s_ecCallback = callback = new ContextCallback(ExecutionContextCallback);
- ExecutionContext.Run(ec, callback, this, true);
+ ExecutionContext.Run(ec, s_ecCallback, this);
}
if (AsyncCausalityTracer.LoggingOn)
@@ -2810,16 +2476,7 @@ namespace System.Threading.Tasks
}
}
- // Cached callback delegate that's lazily initialized due to ContextCallback being SecurityCritical
- private static ContextCallback s_ecCallback;
-
- private static void ExecutionContextCallback(object obj)
- {
- Task task = obj as Task;
- Debug.Assert(task != null, "expected a task object");
- task.Execute();
- }
-
+ private static readonly ContextCallback s_ecCallback = obj => ((Task)obj).Execute();
/// <summary>
/// The actual code which invokes the body of the task. This can be overriden in derived types.
@@ -2844,21 +2501,6 @@ namespace System.Threading.Tasks
}
/// <summary>
- /// Alternate InnerInvoke prototype to be called from ExecuteSelfReplicating() so that
- /// the Parallel Debugger can discover the actual task being invoked.
- /// Details: Here, InnerInvoke is actually being called on the rootTask object while we are actually executing the
- /// childTask. And the debugger needs to discover the childTask, so we pass that down as an argument.
- /// The NoOptimization and NoInlining flags ensure that the childTask pointer is retained, and that this
- /// function appears on the callstack.
- /// </summary>
- /// <param name="childTask"></param>
- [MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
- internal void InnerInvokeWithArg(Task childTask)
- {
- InnerInvoke();
- }
-
- /// <summary>
/// Performs whatever handling is necessary for an unhandled exception. Normally
/// this just entails adding the exception to the holder object.
/// </summary>
@@ -2917,10 +2559,9 @@ namespace System.Threading.Tasks
/// true to attempt to marshal the continuation back to the original context captured; otherwise, false.
/// </param>
/// <param name="flowExecutionContext">Whether to flow ExecutionContext across the await.</param>
- /// <param name="stackMark">A stack crawl mark tied to execution context.</param>
/// <exception cref="System.InvalidOperationException">The awaiter was not properly initialized.</exception>
internal void SetContinuationForAwait(
- Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext, ref StackCrawlMark stackMark)
+ Action continuationAction, bool continueOnCapturedContext, bool flowExecutionContext)
{
Contract.Requires(continuationAction != null);
@@ -2941,7 +2582,7 @@ namespace System.Threading.Tasks
var syncCtx = SynchronizationContext.CurrentNoFlow;
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
{
- tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark);
+ tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext);
}
else
{
@@ -2950,7 +2591,7 @@ namespace System.Threading.Tasks
var scheduler = TaskScheduler.InternalCurrent;
if (scheduler != null && scheduler != TaskScheduler.Default)
{
- tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark);
+ tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext);
}
}
}
@@ -2962,7 +2603,7 @@ namespace System.Threading.Tasks
// ExecutionContext, we need to capture it and wrap it in an AwaitTaskContinuation.
// Otherwise, we're targeting the default scheduler and we don't need to flow ExecutionContext, so
// we don't actually need a continuation object. We can just store/queue the action itself.
- tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true, stackMark: ref stackMark);
+ tc = new AwaitTaskContinuation(continuationAction, flowExecutionContext: true);
}
// Now register the continuation, and if we couldn't register it because the task is already completing,
@@ -3190,7 +2831,7 @@ namespace System.Threading.Tasks
Task currentTask = Task.InternalCurrent;
etwLog.TaskWaitBegin(
(currentTask != null ? currentTask.m_taskScheduler.Id : TaskScheduler.Default.Id), (currentTask != null ? currentTask.Id : 0),
- this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0, System.Threading.Thread.GetDomainID());
+ this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0);
}
bool returnValue = IsCompleted;
@@ -3377,7 +3018,7 @@ namespace System.Threading.Tasks
}
}
- bool bRequiresAtomicStartTransition = (ts != null && ts.RequiresAtomicStartTransition) || ((Options & (TaskCreationOptions)InternalTaskOptions.SelfReplicating) != 0);
+ bool bRequiresAtomicStartTransition = ts != null && ts.RequiresAtomicStartTransition;
if (!bPopSucceeded && bCancelNonExecutingOnly && bRequiresAtomicStartTransition)
{
@@ -3715,11 +3356,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3742,11 +3381,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -3771,11 +3408,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3806,11 +3441,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -3851,17 +3484,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task> continuationAction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task ContinueWith(Action<Task> continuationAction, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null action
if (continuationAction == null)
@@ -3882,8 +3513,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromTask(
this, continuationAction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -3913,11 +3543,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationAction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -3941,11 +3569,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -3971,11 +3597,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4007,11 +3631,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4053,17 +3675,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task ContinueWith(Action<Task, Object> continuationAction, Object state, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith(continuationAction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task ContinueWith(Action<Task, Object> continuationAction, Object state, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null action
if (continuationAction == null)
@@ -4084,8 +3704,7 @@ namespace System.Threading.Tasks
Task continuationTask = new ContinuationTaskFromTask(
this, continuationAction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -4118,12 +3737,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken),
- TaskContinuationOptions.None, ref stackMark);
+ TaskContinuationOptions.None);
}
@@ -4150,11 +3767,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -4182,11 +3797,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4220,11 +3833,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4268,17 +3879,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null function
if (continuationFunction == null)
@@ -4299,8 +3908,7 @@ namespace System.Threading.Tasks
Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
this, continuationFunction, null,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -4333,12 +3941,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="continuationFunction"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken),
- TaskContinuationOptions.None, ref stackMark);
+ TaskContinuationOptions.None);
}
@@ -4366,11 +3972,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, cancellationToken, TaskContinuationOptions.None);
}
/// <summary>
@@ -4399,11 +4003,9 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="scheduler"/> argument is null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, scheduler, default(CancellationToken), TaskContinuationOptions.None);
}
/// <summary>
@@ -4438,11 +4040,9 @@ namespace System.Threading.Tasks
/// The <paramref name="continuationOptions"/> argument specifies an invalid value for <see
/// cref="T:System.Threading.Tasks.TaskContinuationOptions">TaskContinuationOptions</see>.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskContinuationOptions continuationOptions)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, TaskScheduler.Current, default(CancellationToken), continuationOptions);
}
/// <summary>
@@ -4487,17 +4087,15 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">The provided <see cref="System.Threading.CancellationToken">CancellationToken</see>
/// has already been disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, CancellationToken cancellationToken,
TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions, ref stackMark);
+ return ContinueWith<TResult>(continuationFunction, state, scheduler, cancellationToken, continuationOptions);
}
// Same as the above overload, just with a stack mark parameter.
private Task<TResult> ContinueWith<TResult>(Func<Task, Object, TResult> continuationFunction, Object state, TaskScheduler scheduler,
- CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, ref StackCrawlMark stackMark)
+ CancellationToken cancellationToken, TaskContinuationOptions continuationOptions)
{
// Throw on continuation with null function
if (continuationFunction == null)
@@ -4518,8 +4116,7 @@ namespace System.Threading.Tasks
Task<TResult> continuationTask = new ContinuationResultTaskFromTask<TResult>(
this, continuationFunction, state,
- creationOptions, internalOptions,
- ref stackMark
+ creationOptions, internalOptions
);
// Register the continuation. If synchronous execution is requested, this may
@@ -5207,49 +4804,6 @@ namespace System.Threading.Tasks
}
/// <summary>
- /// Internal WaitAll implementation which is meant to be used with small number of tasks,
- /// optimized for Parallel.Invoke and other structured primitives.
- /// </summary>
- internal static void FastWaitAll(Task[] tasks)
- {
- Contract.Requires(tasks != null);
-
- List<Exception> exceptions = null;
-
- // Collects incomplete tasks in "waitedOnTaskList" and their cooperative events in "cooperativeEventList"
- for (int i = tasks.Length - 1; i >= 0; i--)
- {
- if (!tasks[i].IsCompleted)
- {
- // Just attempting to inline here... result doesn't matter.
- // We'll do a second pass to do actual wait on each task, and to aggregate their exceptions.
- // If the task is inlined here, it will register as IsCompleted in the second pass
- // and will just give us the exception.
- tasks[i].WrappedTryRunInline();
- }
- }
-
- // Wait on the tasks.
- for (int i = tasks.Length - 1; i >= 0; i--)
- {
- var task = tasks[i];
- task.SpinThenBlockingWait(Timeout.Infinite, default(CancellationToken));
- AddExceptionsForCompletedTask(ref exceptions, task);
-
- // Note that unlike other wait code paths, we do not check
- // task.NotifyDebuggerOfWaitCompletionIfNecessary() here, because this method is currently
- // only used from contexts where the tasks couldn't have that bit set, namely
- // Parallel.Invoke. If that ever changes, such checks should be added here.
- }
-
- // If one or more threw exceptions, aggregate them.
- if (exceptions != null)
- {
- ThrowHelper.ThrowAggregateException(exceptions);
- }
- }
-
- /// <summary>
/// This internal function is only meant to be called by WaitAll()
/// If the completed task is canceled or it has other exceptions, here we will add those
/// into the passed in exception list (which will be lazily initialized here).
@@ -5582,12 +5136,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="action"/> parameter was null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task Run(Action action)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(null, action, null, default(CancellationToken), TaskScheduler.Default,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
/// <summary>
@@ -5602,12 +5154,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">
/// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task Run(Action action, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task.InternalStartNew(null, action, null, cancellationToken, TaskScheduler.Default,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None);
}
/// <summary>
@@ -5618,12 +5168,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ArgumentNullException">
/// The <paramref name="function"/> parameter was null.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task<TResult> Run<TResult>(Func<TResult> function)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(null, function, default(CancellationToken),
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
}
/// <summary>
@@ -5638,12 +5186,10 @@ namespace System.Threading.Tasks
/// <exception cref="T:System.ObjectDisposedException">
/// The <see cref="T:System.CancellationTokenSource"/> associated with <paramref name="cancellationToken"/> was disposed.
/// </exception>
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
public static Task<TResult> Run<TResult>(Func<TResult> function, CancellationToken cancellationToken)
{
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
return Task<TResult>.StartNew(null, function, cancellationToken,
- TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default, ref stackMark);
+ TaskCreationOptions.DenyChildAttach, InternalTaskOptions.None, TaskScheduler.Default);
}
/// <summary>
@@ -6693,102 +6239,6 @@ namespace System.Threading.Tasks
public TaskStatus Status { get { return m_task.Status; } }
}
- // Special purpose derivation of Task that supports limited replication through
- // overriding the ShouldReplicate() method. This is used by the Parallel.For/ForEach
- // methods.
- internal class ParallelForReplicatingTask : Task
- {
- // Member variables
- private int m_replicationDownCount; // downcounter to control replication
-
- //
- // Constructors
- //
-
- [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
- internal ParallelForReplicatingTask(
- ParallelOptions parallelOptions, Action action, TaskCreationOptions creationOptions, InternalTaskOptions internalOptions)
- : base(action, null, Task.InternalCurrent, default(CancellationToken), creationOptions, internalOptions | InternalTaskOptions.SelfReplicating, null)
- {
- // Compute the down count based on scheduler/DOP info in parallelOptions.
- m_replicationDownCount = parallelOptions.EffectiveMaxConcurrencyLevel;
-
- StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
- PossiblyCaptureContext(ref stackMark);
- }
-
-
- // Controls degree of replication. If downcounter is initialized to -1, then
- // replication will be allowed to "run wild". Otherwise, this method decrements
- // the downcounter each time it is called, calling false when it is called with
- // a zero downcounter. This method returning false effectively ends the replication
- // of the associated ParallelForReplicatingTask.
- internal override bool ShouldReplicate()
- {
- if (m_replicationDownCount == -1) return true; // "run wild"
-
- if (m_replicationDownCount > 0) // Decrement and return true if not called with 0 downcount
- {
- m_replicationDownCount--;
- return true;
- }
-
- return false; // We're done replicating
- }
-
- internal override Task CreateReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica)
- {
- return new ParallelForReplicaTask(taskReplicaDelegate, stateObject, parentTask, taskScheduler,
- creationOptionsForReplica, internalOptionsForReplica);
- }
-
-
- }
-
- internal class ParallelForReplicaTask : Task
- {
- internal object m_stateForNextReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to save state they want to be picked up by the next replica queued to the same thread
-
- internal object m_stateFromPreviousReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to save state they want to be picked up by the next replica queued to the same thread
-
- internal Task m_handedOverChildReplica; // some replicas may quit prematurely, in which case they will use this variable
- // to hand over the child replica they had queued to the next task that will replace them
-
- internal ParallelForReplicaTask(Action<object> taskReplicaDelegate, Object stateObject, Task parentTask, TaskScheduler taskScheduler,
- TaskCreationOptions creationOptionsForReplica, InternalTaskOptions internalOptionsForReplica) :
- base(taskReplicaDelegate, stateObject, parentTask, default(CancellationToken), creationOptionsForReplica, internalOptionsForReplica, taskScheduler)
- {
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal override Object SavedStateForNextReplica
- {
- get { return m_stateForNextReplica; }
-
- set { m_stateForNextReplica = value; }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to pass on state to the next replica
- internal override Object SavedStateFromPreviousReplica
- {
- get { return m_stateFromPreviousReplica; }
-
- set { m_stateFromPreviousReplica = value; }
- }
-
- // Allows internal deriving classes to support replicas that exit prematurely and want to hand over the child replica that they
- // had queued, so that the replacement replica can work with that child task instead of queuing up yet another one
- internal override Task HandedOverChildReplica
- {
- get { return m_handedOverChildReplica; }
-
- set { m_handedOverChildReplica = value; }
- }
- }
-
/// <summary>
/// Specifies flags that control optional behavior for the creation and execution of tasks.
/// </summary>
@@ -6856,10 +6306,8 @@ namespace System.Threading.Tasks
/// <summary>Used to filter out internal vs. public task creation options.</summary>
InternalOptionsMask = 0x0000FF00,
- ChildReplica = 0x0100,
ContinuationTask = 0x0200,
PromiseTask = 0x0400,
- SelfReplicating = 0x0800,
/// <summary>
/// Store the presence of TaskContinuationOptions.LazyCancellation, since it does not directly