summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2019-01-24 21:56:41 +0100
committerJan Kotas <jkotas@microsoft.com>2019-01-24 12:56:41 -0800
commitef52964bb6db4687265abda8be65aa4c930796d0 (patch)
tree563d99d76f659e9a3f2058e92c553d38359891f8
parentaab30e3248b882ecad122127f3d60a2ce9ea14a6 (diff)
downloadcoreclr-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.csproj1
-rw-r--r--src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems1
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs58
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs54
-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);