| File: WeakReferenceHelpers.cs | Web Access |
| Project: src\aspnetcore\src\DataProtection\Cryptography.Internal\src\Microsoft.AspNetCore.Cryptography.Internal.csproj (Microsoft.AspNetCore.Cryptography.Internal) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Threading; namespace Microsoft.AspNetCore.Cryptography; internal static class WeakReferenceHelpers { public static T GetSharedInstance<T>(ref WeakReference<T>? weakReference, Func<T> factory) where T : class, IDisposable { // First, see if the WR already exists and points to a live object. WeakReference<T>? existingWeakRef = Volatile.Read(ref weakReference); T? newTarget = null; WeakReference<T>? newWeakRef = null; while (true) { if (existingWeakRef != null) { if (weakReference!.TryGetTarget(out var existingTarget)) { // If we created a new target on a previous iteration of the loop but we // weren't able to store the target into the desired location, dispose of it now. newTarget?.Dispose(); return existingTarget; } } // If the existing WR didn't point anywhere useful and this is our // first iteration through the loop, create the new target and WR now. if (newTarget == null) { newTarget = factory(); Debug.Assert(newTarget != null); newWeakRef = new WeakReference<T>(newTarget); } Debug.Assert(newWeakRef != null); // Try replacing the existing WR with our newly-created one. WeakReference<T>? currentWeakRef = Interlocked.CompareExchange(ref weakReference, newWeakRef, existingWeakRef); if (ReferenceEquals(currentWeakRef, existingWeakRef)) { // success, 'weakReference' now points to our newly-created WR return newTarget; } // If we got to this point, somebody beat us to creating a new WR. // We'll loop around and check it for validity. Debug.Assert(currentWeakRef != null); existingWeakRef = currentWeakRef; } } }