diff options
author | Marek Safar <marek.safar@gmail.com> | 2019-01-24 21:56:41 +0100 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2019-01-24 12:56:41 -0800 |
commit | ef52964bb6db4687265abda8be65aa4c930796d0 (patch) | |
tree | 563d99d76f659e9a3f2058e92c553d38359891f8 | |
parent | aab30e3248b882ecad122127f3d60a2ce9ea14a6 (diff) | |
download | coreclr-ef52964bb6db4687265abda8be65aa4c930796d0.tar.gz coreclr-ef52964bb6db4687265abda8be65aa4c930796d0.tar.bz2 coreclr-ef52964bb6db4687265abda8be65aa4c930796d0.zip |
Move TaskContinuation to shared partition (#22167)
* Move TaskContinuation to shared partition
* Remove TASK_STATE_THREAD_WAS_ABORTED from Task
* Use already existing ThrowAsync
-rw-r--r-- | src/System.Private.CoreLib/System.Private.CoreLib.csproj | 1 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems | 1 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs | 58 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs | 54 | ||||
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs (renamed from src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs) | 78 |
5 files changed, 79 insertions, 113 deletions
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 04b374f7f5..e293399be8 100644 --- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -275,7 +275,6 @@ <Compile Include="$(BclSourcesRoot)\System\Threading\Monitor.cs" /> <Compile Include="$(BclSourcesRoot)\System\Threading\Overlapped.cs" /> <Compile Include="$(BclSourcesRoot)\System\Threading\SynchronizationContext.cs" /> - <Compile Include="$(BclSourcesRoot)\System\Threading\Tasks\TaskContinuation.cs" /> <Compile Include="$(BclSourcesRoot)\System\Threading\Thread.cs" /> <Compile Include="$(BclSourcesRoot)\System\Threading\ThreadPool.CoreCLR.cs" /> <Compile Include="$(BclSourcesRoot)\System\Threading\Timer.cs" /> diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index 6c5da60bb8..7640d419f9 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -786,6 +786,7 @@ <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\Task.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskCanceledException.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskCompletionSource.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskContinuation.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskExceptionHolder.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskExtensions.cs" /> <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskFactory.cs" /> diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs index 21f181031d..217f5304a6 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs @@ -14,14 +14,10 @@ using System.Diagnostics; using System.Diagnostics.Tracing; using System.Reflection; using System.Runtime.ExceptionServices; -#if FEATURE_COMINTEROP -using System.Runtime.InteropServices.WindowsRuntime; -#endif // FEATURE_COMINTEROP using System.Threading; using System.Threading.Tasks; using System.Text; using Internal.Runtime.CompilerServices; -using Internal.Runtime.Augments; #if CORERT using Thread = Internal.Runtime.Augments.RuntimeThread; @@ -131,7 +127,7 @@ namespace System.Runtime.CompilerServices // and decrement its outstanding operation count. try { - AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: _synchronizationContext); + System.Threading.Tasks.Task.ThrowAsync(exception, targetContext: _synchronizationContext); } finally { @@ -143,7 +139,7 @@ namespace System.Runtime.CompilerServices // Otherwise, queue the exception to be thrown on the ThreadPool. This will // result in a crash unless legacy exception behavior is enabled by a config // file or a CLR host. - AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: null); + System.Threading.Tasks.Task.ThrowAsync(exception, targetContext: null); } // The exception was propagated already; we don't need or want to fault the builder, just mark it as completed. @@ -162,7 +158,7 @@ namespace System.Runtime.CompilerServices { // If the interaction with the SynchronizationContext goes awry, // fall back to propagating on the ThreadPool. - AsyncMethodBuilderCore.ThrowAsync(exc, targetContext: null); + Task.ThrowAsync(exc, targetContext: null); } } @@ -369,7 +365,7 @@ namespace System.Runtime.CompilerServices } catch (Exception e) { - AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null); + System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); } } @@ -415,7 +411,7 @@ namespace System.Runtime.CompilerServices // exceptions well at that location in the state machine, especially if the exception may occur // after the ValueTaskAwaiter already successfully hooked up the callback, in which case it's possible // two different flows of execution could end up happening in the same async method call. - AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null); + System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); } } else @@ -427,7 +423,7 @@ namespace System.Runtime.CompilerServices } catch (Exception e) { - AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null); + System.Threading.Tasks.Task.ThrowAsync(e, targetContext: null); } } } @@ -1069,48 +1065,6 @@ namespace System.Runtime.CompilerServices internal static Task TryGetContinuationTask(Action continuation) => (continuation?.Target as ContinuationWrapper)?._innerTask; - /// <summary>Throws the exception on the ThreadPool.</summary> - /// <param name="exception">The exception to propagate.</param> - /// <param name="targetContext">The target context on which to propagate the exception. Null to use the ThreadPool.</param> - internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) - { - // Capture the exception into an ExceptionDispatchInfo so that its - // stack trace and Watson bucket info will be preserved - var edi = ExceptionDispatchInfo.Capture(exception); - - // If the user supplied a SynchronizationContext... - if (targetContext != null) - { - try - { - // Post the throwing of the exception to that context, and return. - targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi); - return; - } - catch (Exception postException) - { - // If something goes horribly wrong in the Post, we'll - // propagate both exceptions on the ThreadPool - edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException)); - } - } - -#if CORERT - RuntimeAugments.ReportUnhandledException(edi.SourceException); -#else - -#if FEATURE_COMINTEROP - // If we have the new error reporting APIs, report this error. - if (WindowsRuntimeMarshal.ReportUnhandledError(edi.SourceException)) - return; -#endif // FEATURE_COMINTEROP - - // Propagate the exception(s) on the ThreadPool - ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state).Throw(), edi); - -#endif // CORERT - } - /// <summary> /// Logically we pass just an Action (delegate) to a task for its action to 'ContinueWith' when it completes. /// However debuggers and profilers need more information about what that action is. (In particular what diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index e518a8471d..6f49037284 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -184,7 +184,6 @@ namespace System.Threading.Tasks internal const int TASK_STATE_RAN_TO_COMPLETION = 0x1000000; //bin: 0000 0001 0000 0000 0000 0000 0000 0000 internal const int TASK_STATE_WAITINGFORACTIVATION = 0x2000000; //bin: 0000 0010 0000 0000 0000 0000 0000 0000 internal const int TASK_STATE_COMPLETION_RESERVED = 0x4000000; //bin: 0000 0100 0000 0000 0000 0000 0000 0000 - internal const int TASK_STATE_THREAD_WAS_ABORTED = 0x8000000; //bin: 0000 1000 0000 0000 0000 0000 0000 0000 internal const int TASK_STATE_WAIT_COMPLETION_NOTIFICATION = 0x10000000; //bin: 0001 0000 0000 0000 0000 0000 0000 0000 //This could be moved to InternalTaskOptions enum internal const int TASK_STATE_EXECUTIONCONTEXT_IS_NULL = 0x20000000; //bin: 0010 0000 0000 0000 0000 0000 0000 0000 @@ -1136,9 +1135,8 @@ namespace System.Threading.Tasks } catch (Exception e) { - // we 1) either received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown - // 2) or a a ThreadAbortException, which we need to skip here, because it would already have been handled in Task.Execute - if (!taskQueued && !(e is ThreadAbortException)) + // we received an unexpected exception originating from a custom scheduler, which needs to be wrapped in a TSE and thrown + if (!taskQueued) { // We had a problem with TryRunInline() or QueueTask(). // Record the exception, marking ourselves as Completed/Faulted. @@ -1160,7 +1158,7 @@ namespace System.Threading.Tasks // And re-throw. throw tse; } - // We had a problem with waiting or this is a thread abort. Just re-throw. + // We had a problem with waiting. Just re-throw. else throw; } } @@ -1964,6 +1962,48 @@ namespace System.Threading.Tasks } } + /// <summary>Throws the exception on the ThreadPool.</summary> + /// <param name="exception">The exception to propagate.</param> + /// <param name="targetContext">The target context on which to propagate the exception. Null to use the ThreadPool.</param> + internal static void ThrowAsync(Exception exception, SynchronizationContext targetContext) + { + // Capture the exception into an ExceptionDispatchInfo so that its + // stack trace and Watson bucket info will be preserved + var edi = ExceptionDispatchInfo.Capture(exception); + + // If the user supplied a SynchronizationContext... + if (targetContext != null) + { + try + { + // Post the throwing of the exception to that context, and return. + targetContext.Post(state => ((ExceptionDispatchInfo)state).Throw(), edi); + return; + } + catch (Exception postException) + { + // If something goes horribly wrong in the Post, we'll + // propagate both exceptions on the ThreadPool + edi = ExceptionDispatchInfo.Capture(new AggregateException(exception, postException)); + } + } + +#if CORERT + RuntimeAugments.ReportUnhandledException(edi.SourceException); +#else + +#if FEATURE_COMINTEROP + // If we have the new error reporting APIs, report this error. + if (System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.ReportUnhandledError(edi.SourceException)) + return; +#endif + + // Propagate the exception(s) on the ThreadPool + ThreadPool.QueueUserWorkItem(state => ((ExceptionDispatchInfo)state).Throw(), edi); + +#endif // CORERT + } + /// <summary> /// Checks whether this is an attached task, and whether we are being called by the parent task. /// And sets the TASK_STATE_EXCEPTIONOBSERVEDBYPARENT status flag based on that. @@ -3202,9 +3242,7 @@ namespace System.Threading.Tasks if (AsyncCausalityTracer.LoggingOn) AsyncCausalityTracer.TraceSynchronousWorkStart(this, CausalitySynchronousWork.CompletionNotification); - // Skip synchronous execution of continuations if this task's thread was aborted - bool canInlineContinuations = !(((m_stateFlags & TASK_STATE_THREAD_WAS_ABORTED) != 0) || - ((m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) != 0)); + bool canInlineContinuations = (m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) == 0; switch (continuationObject) { diff --git a/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs index 73e7ef114e..8933f219f2 100644 --- a/src/System.Private.CoreLib/src/System/Threading/Tasks/TaskContinuation.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @@ -2,23 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// -// -// -// Implementation of task continuations, TaskContinuation, and its descendants. -// -// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- - using System.Security; using System.Diagnostics; using System.Runtime.ExceptionServices; using System.Runtime.CompilerServices; -using System.Threading; -#if FEATURE_COMINTEROP -using System.Runtime.InteropServices.WindowsRuntime; -#endif // FEATURE_COMINTEROP +#if CORERT +using Thread = Internal.Runtime.Augments.RuntimeThread; +#endif namespace System.Threading.Tasks { @@ -258,18 +249,19 @@ namespace System.Threading.Tasks // Either TryRunInline() or QueueTask() threw an exception. Record the exception, marking the task as Faulted. // However if it was a ThreadAbortException coming from TryRunInline we need to skip here, // because it would already have been handled in Task.Execute() - if (!(e is ThreadAbortException && - (task.m_stateFlags & Task.TASK_STATE_THREAD_WAS_ABORTED) != 0)) // this ensures TAEs from QueueTask will be wrapped in TSE - { - TaskSchedulerException tse = new TaskSchedulerException(e); - task.AddException(tse); - task.Finish(false); - } - + TaskSchedulerException tse = new TaskSchedulerException(e); + task.AddException(tse); + task.Finish(false); // Don't re-throw. } } + // + // This helper routine is targeted by the debugger. + // +#if PROJECTN + [DependencyReductionRoot] +#endif internal abstract Delegate[] GetDelegateContinuationsForDebugger(); } @@ -370,7 +362,7 @@ namespace System.Threading.Tasks internal sealed class SynchronizationContextAwaitTaskContinuation : AwaitTaskContinuation { /// <summary>SendOrPostCallback delegate to invoke the action.</summary> - private readonly static SendOrPostCallback s_postCallback = state => ((Action)state)(); // can't use InvokeAction as it's SecurityCritical + private static readonly SendOrPostCallback s_postCallback = state => ((Action)state)(); // can't use InvokeAction as it's SecurityCritical /// <summary>Cached delegate for PostAction</summary> private static ContextCallback s_postActionCallback; /// <summary>The context with which to run the action.</summary> @@ -499,8 +491,14 @@ namespace System.Threading.Tasks // The target scheduler may still deny us from executing on this thread, in which case this'll be queued. var task = CreateTask(state => { - try { ((Action)state)(); } - catch (Exception exc) { ThrowAsyncIfNecessary(exc); } + try + { + ((Action)state)(); + } + catch (Exception exception) + { + Task.ThrowAsync(exception, targetContext: null); + } }, m_action, m_scheduler); if (inlineIfPossible) @@ -629,7 +627,7 @@ namespace System.Threading.Tasks return; } - Guid savedActivityId = Guid.Empty; + Guid savedActivityId = default; if (etwLog.TasksSetActivityIds && m_continuationId != 0) { Guid activityId = TplEtwProvider.CreateGuidForTaskID(m_continuationId); @@ -699,9 +697,9 @@ namespace System.Threading.Tasks ExecutionContext.RunInternal(context, callback, state); } } - catch (Exception exc) // we explicitly do not request handling of dangerous exceptions like AVs + catch (Exception exception) // we explicitly do not request handling of dangerous exceptions like AVs { - ThrowAsyncIfNecessary(exc); + Task.ThrowAsync(exception, targetContext: null); } finally { @@ -741,7 +739,7 @@ namespace System.Threading.Tasks } catch (Exception exception) { - ThrowAsyncIfNecessary(exception); + Task.ThrowAsync(exception, targetContext: null); } finally { @@ -793,7 +791,7 @@ namespace System.Threading.Tasks } catch (Exception exception) { - ThrowAsyncIfNecessary(exception); + Task.ThrowAsync(exception, targetContext: null); } finally { @@ -818,30 +816,6 @@ namespace System.Threading.Tasks ThreadPool.UnsafeQueueUserWorkItemInternal(atc, preferLocal: true); } - /// <summary>Throws the exception asynchronously on the ThreadPool.</summary> - /// <param name="exc">The exception to throw.</param> - protected static void ThrowAsyncIfNecessary(Exception exc) - { - // Awaits should never experience an exception (other than an TAE or ADUE), - // unless a malicious user is explicitly passing a throwing action into the TaskAwaiter. - // We don't want to allow the exception to propagate on this stack, as it'll emerge in random places, - // and we can't fail fast, as that would allow for elevation of privilege. - // - // If unhandled error reporting APIs are available use those, otherwise since this - // would have executed on the thread pool otherwise, let it propagate there. - - if (!(exc is ThreadAbortException)) - { -#if FEATURE_COMINTEROP - if (!WindowsRuntimeMarshal.ReportUnhandledError(exc)) -#endif // FEATURE_COMINTEROP - { - var edi = ExceptionDispatchInfo.Capture(exc); - ThreadPool.QueueUserWorkItem(s => ((ExceptionDispatchInfo)s).Throw(), edi); - } - } - } - internal override Delegate[] GetDelegateContinuationsForDebugger() { Debug.Assert(m_action != null); |