Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit ac25be6

Browse files
authored
Fix use of AddTo/RemoveFromActiveTasks in async methods (#25915)
When we rewrote the async methods implementation with AsyncStateMachineBox, we neglected to call AddToActiveTasks if the debugger is paying attention to tasks. This hasn't mattered as the debugger's support for Tasks hasn't worked for other reasons in .NET Core, but there is now a renewed focus on it, and this is preventing some of that support from working. This change is a minimal fix to ensure that we're adding the state machine box task when it's created and removing it when it completes. Post-3.0, we should look at overhauling this, e.g. to clean up a lot of this logging and tracking that's done, to use a weak table in order to avoid keeping task objects alive artificially if they're dropped without completing by the developer code, etc. This only affects when the debugger is attached, as the s_asyncDebuggingEnabled field is only ever set by the debugger.
1 parent 3d4806e commit ac25be6

File tree

1 file changed

+15
-20
lines changed

1 file changed

+15
-20
lines changed

src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/AsyncMethodBuilder.cs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,18 @@ private IAsyncStateMachineBox GetStateMachineBox<TStateMachine>(
517517
box.StateMachine = stateMachine;
518518
box.Context = currentContext;
519519

520-
// Finally, log the creation of the state machine box object / task for this async method.
520+
// Log the creation of the state machine box object / task for this async method.
521521
if (AsyncCausalityTracer.LoggingOn)
522522
{
523523
AsyncCausalityTracer.TraceOperationCreation(box, "Async: " + stateMachine.GetType().Name);
524524
}
525525

526+
// And if async debugging is enabled, track the task.
527+
if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
528+
{
529+
System.Threading.Tasks.Task.AddToActiveTasks(box);
530+
}
531+
526532
return box;
527533
}
528534

@@ -618,6 +624,12 @@ private void MoveNext(Thread? threadPoolThread)
618624

619625
if (IsCompleted)
620626
{
627+
// If async debugging is enabled, remove the task from tracking.
628+
if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
629+
{
630+
System.Threading.Tasks.Task.RemoveFromActiveTasks(this);
631+
}
632+
621633
// Clear out state now that the async method has completed.
622634
// This avoids keeping arbitrary state referenced by lifted locals
623635
// if this Task / state machine box is held onto.
@@ -716,31 +728,14 @@ private void SetExistingTaskResult([AllowNull] TResult result)
716728
{
717729
Debug.Assert(m_task != null, "Expected non-null task");
718730

719-
if (AsyncCausalityTracer.LoggingOn || System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
720-
{
721-
LogExistingTaskCompletion();
722-
}
723-
724-
if (!m_task.TrySetResult(result))
725-
{
726-
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
727-
}
728-
}
729-
730-
/// <summary>Handles logging for the successful completion of an operation.</summary>
731-
private void LogExistingTaskCompletion()
732-
{
733-
Debug.Assert(m_task != null);
734-
735731
if (AsyncCausalityTracer.LoggingOn)
736732
{
737733
AsyncCausalityTracer.TraceOperationCompletion(m_task, AsyncCausalityStatus.Completed);
738734
}
739735

740-
// only log if we have a real task that was previously created
741-
if (System.Threading.Tasks.Task.s_asyncDebuggingEnabled)
736+
if (!m_task.TrySetResult(result))
742737
{
743-
System.Threading.Tasks.Task.RemoveFromActiveTasks(m_task);
738+
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.TaskT_TransitionToFinal_AlreadyCompleted);
744739
}
745740
}
746741

0 commit comments

Comments
 (0)