diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2017-02-10 20:35:12 +0900 |
commit | 4b11dc566a5bbfa1378d6266525c281b028abcc8 (patch) | |
tree | b48831a898906734f8884d08b6e18f1144ee2b82 /src/mscorlib/src/System/Threading/Tasks/Task.cs | |
parent | db20f3f1bb8595633a7e16c8900fd401a453a6b5 (diff) | |
download | coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.gz coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.tar.bz2 coreclr-4b11dc566a5bbfa1378d6266525c281b028abcc8.zip |
Imported Upstream version 1.0.0.9910upstream/1.0.0.9910
Diffstat (limited to 'src/mscorlib/src/System/Threading/Tasks/Task.cs')
-rw-r--r-- | src/mscorlib/src/System/Threading/Tasks/Task.cs | 716 |
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 |