Skip to content

Commit

Permalink
Add test for leaking JoinableTask via ExecutionContext
Browse files Browse the repository at this point in the history
  • Loading branch information
AArnott committed Aug 12, 2018
1 parent 2ef2a86 commit aa254f1
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/Microsoft.VisualStudio.Threading.Tests/JoinableTaskTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -3629,6 +3630,24 @@ await Task.Run(async delegate
});
}

[Fact]
public void ExecutionContext_DoesNotLeakJoinableTask()
{
var longLivedTaskReleaser = new AsyncManualResetEvent();
WeakReference weakValue = this.ExecutionContext_DoesNotLeakJoinableTask_Helper(longLivedTaskReleaser);
try
{
// Assert that since no one wants the JoinableTask or its result any more, it has been released.
GC.Collect();
Assert.False(weakValue.IsAlive);
}
finally
{
// Allow completion of our long-lived task.
longLivedTaskReleaser.Set();
}
}

protected override JoinableTaskContext CreateJoinableTaskContext()
{
return new DerivedJoinableTaskContext();
Expand Down Expand Up @@ -3732,6 +3751,32 @@ private void PrintActiveTasksReport(JoinableTaskContext context = null)
this.Logger.WriteLine(report.Content);
}

[MethodImpl(MethodImplOptions.NoInlining)] // must not be inlined so that locals are guaranteed to be freed.
private WeakReference ExecutionContext_DoesNotLeakJoinableTask_Helper(AsyncManualResetEvent releaser)
{
object leakedValue = new object();
WeakReference weakValue = new WeakReference(leakedValue);
Task longLivedTask = null;

this.asyncPump.RunAsync(delegate
{
// Spin off a task that will "capture" the current running JoinableTask
longLivedTask = Task.Factory.StartNew(
async r =>
{
await ((AsyncManualResetEvent)r).WaitAsync();
},
releaser,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default).Unwrap();

return Task.FromResult(leakedValue);
});

return weakValue;
}

/// <summary>
/// Simulates COM message pump reentrancy causing some unrelated work to "pump in" on top of a synchronously blocking wait.
/// </summary>
Expand Down

0 comments on commit aa254f1

Please sign in to comment.