From d2796c6a8751b32bd5952976c1663f969720a482 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 12 Aug 2018 11:21:11 -0700 Subject: [PATCH] Stop leaking JoinableTask via ExecutionContext Fixes #274 and gets the recently added test to pass --- .../JoinableTask.cs | 21 +++++++++++++++++++ .../JoinableTaskContext.cs | 12 ++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.VisualStudio.Threading/JoinableTask.cs b/src/Microsoft.VisualStudio.Threading/JoinableTask.cs index b5116e336..a58849e3c 100644 --- a/src/Microsoft.VisualStudio.Threading/JoinableTask.cs +++ b/src/Microsoft.VisualStudio.Threading/JoinableTask.cs @@ -120,6 +120,11 @@ public partial class JoinableTask [DebuggerBrowsable(DebuggerBrowsableState.Never)] private Delegate initialDelegate; + /// + /// Backing field for the property. + /// + private WeakReference weakSelf; + /// /// Initializes a new instance of the class. /// @@ -332,6 +337,22 @@ internal SynchronizationContext ApplicableJobSyncContext } } + /// + /// Gets a weak reference to this object. + /// + internal WeakReference WeakSelf + { + get + { + if (this.weakSelf == null) + { + this.weakSelf = new WeakReference(this); + } + + return this.weakSelf; + } + } + /// /// Gets the flags set on this task. /// diff --git a/src/Microsoft.VisualStudio.Threading/JoinableTaskContext.cs b/src/Microsoft.VisualStudio.Threading/JoinableTaskContext.cs index c62fe9ca4..c83d0b3e1 100644 --- a/src/Microsoft.VisualStudio.Threading/JoinableTaskContext.cs +++ b/src/Microsoft.VisualStudio.Threading/JoinableTaskContext.cs @@ -86,7 +86,7 @@ public partial class JoinableTaskContext : IDisposable /// /// An AsyncLocal value that carries the joinable instance associated with an async operation. /// - private readonly AsyncLocal joinableOperation = new AsyncLocal(); + private readonly AsyncLocal> joinableOperation = new AsyncLocal>(); /// /// The set of tasks that have started but have not yet completed. @@ -251,8 +251,14 @@ internal object SyncContextLock /// internal JoinableTask AmbientTask { - get { return this.joinableOperation.Value; } - set { this.joinableOperation.Value = value; } + get + { + JoinableTask result = null; + this.joinableOperation.Value?.TryGetTarget(out result); + return result; + } + + set => this.joinableOperation.Value = value?.WeakSelf; } ///