Skip to content

Commit

Permalink
Crash the process on unexpected failures when creating a JoinableTask
Browse files Browse the repository at this point in the history
Strictly speaking this is not necessary, as an exception would be thrown to the caller and no lingering adverse effects to the state of `JoinableTaskContext` are left behind. But we find this change useful because this is scheduling code and should be very reliable. Recently an `OutOfMemoryException` was thrown from this code (in a process with plenty of memory) and led other code to hang because it didn't expect JTF itself to fail. See #843 for more info on that.
  • Loading branch information
AArnott committed May 5, 2021
1 parent 7c534fa commit 6777035
Showing 1 changed file with 27 additions and 11 deletions.
38 changes: 27 additions & 11 deletions src/Microsoft.VisualStudio.Threading/JoinableTaskFactory.cs
Expand Up @@ -689,21 +689,37 @@ private JoinableTask<T> RunAsync<T>(Func<Task<T>> asyncMethod, bool synchronousl
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "All exceptions are forwarded to the caller by another means.")]
private void ExecuteJob<T>(Func<Task> asyncMethod, JoinableTask job)
{
using (var framework = new RunFramework(this, job))
try
{
Task asyncMethodResult;
try
using (var framework = new RunFramework(this, job))
{
asyncMethodResult = asyncMethod();
}
catch (Exception ex)
{
var tcs = new TaskCompletionSource<T>();
tcs.SetException(ex);
asyncMethodResult = tcs.Task;
Task asyncMethodResult;
try
{
asyncMethodResult = asyncMethod();
}
catch (Exception ex)
{
var tcs = new TaskCompletionSource<T>();
tcs.SetException(ex);
asyncMethodResult = tcs.Task;
}

job.SetWrappedTask(asyncMethodResult);
}
}
catch (Exception ex) when (FailFast(ex))
{
// We use a crashing exception filter to capture all the detail possible (even before unwinding the callstack)
// when an exception is thrown from this critical method.
// In particular, we have seen the WeakReference object that is instantiated by "new RunFramework" throw OutOfMemoryException.
throw Assumes.NotReachable();
}

job.SetWrappedTask(asyncMethodResult);
static bool FailFast(Exception ex)
{
Environment.FailFast("Unexpected exception thrown in critical scheduling code.", ex);
throw Assumes.NotReachable();
}
}

Expand Down

0 comments on commit 6777035

Please sign in to comment.