Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public abstract partial class ComWrappers
private static readonly Guid IID_IWeakReferenceSource = new Guid(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

private static readonly ConditionalWeakTable<object, NativeObjectWrapper> s_rcwTable = new ConditionalWeakTable<object, NativeObjectWrapper>();
private static readonly List<GCHandle> s_referenceTrackerNativeObjectWrapperCache = new List<GCHandle>();
private static readonly HashSet<GCHandle> s_referenceTrackerNativeObjectWrapperCache = new HashSet<GCHandle>();
private static readonly Lock s_nativeObjectWrapperCacheLock = new Lock(useTrivialWaits: true);

private readonly ConditionalWeakTable<object, ManagedObjectWrapperHolder> _ccwTable = new ConditionalWeakTable<object, ManagedObjectWrapperHolder>();
private readonly Lock _lock = new Lock(useTrivialWaits: true);
Expand Down Expand Up @@ -639,7 +640,10 @@ public override void Release()
// Remove the entry from the cache that keeps track of the active NativeObjectWrappers.
if (_nativeObjectWrapperWeakHandle.IsAllocated)
{
s_referenceTrackerNativeObjectWrapperCache.Remove(_nativeObjectWrapperWeakHandle);
using (s_nativeObjectWrapperCacheLock.EnterScope())
{
s_referenceTrackerNativeObjectWrapperCache.Remove(_nativeObjectWrapperWeakHandle);
}
_nativeObjectWrapperWeakHandle.Free();
}

Expand Down Expand Up @@ -986,10 +990,7 @@ private unsafe bool TryGetOrCreateObjectForComInstanceInternal(
throw new NotSupportedException();
}
_rcwCache.Add(identity, wrapper._proxyHandle);
if (wrapper is ReferenceTrackerNativeObjectWrapper referenceTrackerNativeObjectWrapper)
{
s_referenceTrackerNativeObjectWrapperCache.Add(referenceTrackerNativeObjectWrapper._nativeObjectWrapperWeakHandle);
}
AddWrapperToReferenceTrackerHandleCache(wrapper);
return true;
}
}
Expand Down Expand Up @@ -1042,10 +1043,7 @@ private unsafe bool TryGetOrCreateObjectForComInstanceInternal(
wrapper.Release();
throw new NotSupportedException();
}
if (wrapper is ReferenceTrackerNativeObjectWrapper referenceTrackerNativeObjectWrapper)
{
s_referenceTrackerNativeObjectWrapperCache.Add(referenceTrackerNativeObjectWrapper._nativeObjectWrapperWeakHandle);
}
AddWrapperToReferenceTrackerHandleCache(wrapper);
return true;
}

Expand Down Expand Up @@ -1081,17 +1079,25 @@ private unsafe bool TryGetOrCreateObjectForComInstanceInternal(
throw new NotSupportedException();
}
_rcwCache.Add(identity, wrapper._proxyHandle);
if (wrapper is ReferenceTrackerNativeObjectWrapper referenceTrackerNativeObjectWrapper)
{
s_referenceTrackerNativeObjectWrapperCache.Add(referenceTrackerNativeObjectWrapper._nativeObjectWrapperWeakHandle);
}
AddWrapperToReferenceTrackerHandleCache(wrapper);
}
}

return true;
}
#pragma warning restore IDE0060

private static void AddWrapperToReferenceTrackerHandleCache(NativeObjectWrapper wrapper)
{
if (wrapper is ReferenceTrackerNativeObjectWrapper referenceTrackerNativeObjectWrapper)
{
using (s_nativeObjectWrapperCacheLock.EnterScope())
{
s_referenceTrackerNativeObjectWrapperCache.Add(referenceTrackerNativeObjectWrapper._nativeObjectWrapperWeakHandle);
}
}
}

private void RemoveRCWFromCache(IntPtr comPointer, GCHandle expectedValue)
{
using (_lock.EnterScope())
Expand Down Expand Up @@ -1222,17 +1228,21 @@ internal static void ReleaseExternalObjectsFromCurrentThread()
IntPtr contextToken = GetContextToken();

List<object> objects = new List<object>();
foreach (GCHandle weakNativeObjectWrapperHandle in s_referenceTrackerNativeObjectWrapperCache)

using (s_nativeObjectWrapperCacheLock.EnterScope())
{
ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper = Unsafe.As<ReferenceTrackerNativeObjectWrapper?>(weakNativeObjectWrapperHandle.Target);
if (nativeObjectWrapper != null &&
nativeObjectWrapper._contextToken == contextToken)
foreach (GCHandle weakNativeObjectWrapperHandle in s_referenceTrackerNativeObjectWrapperCache)
{
objects.Add(nativeObjectWrapper._proxyHandle.Target);
ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper = Unsafe.As<ReferenceTrackerNativeObjectWrapper?>(weakNativeObjectWrapperHandle.Target);
if (nativeObjectWrapper != null &&
nativeObjectWrapper._contextToken == contextToken)
{
objects.Add(nativeObjectWrapper._proxyHandle.Target);

// Separate the wrapper from the tracker runtime prior to
// passing them.
nativeObjectWrapper.DisconnectTracker();
// Separate the wrapper from the tracker runtime prior to
// passing them.
nativeObjectWrapper.DisconnectTracker();
}
}
}

Expand All @@ -1244,6 +1254,7 @@ internal static unsafe void WalkExternalTrackerObjects()
{
bool walkFailed = false;

// No lock needed to access s_referenceTrackerNativeObjectWrapperCache as this is during GC callback.
foreach (GCHandle weakNativeObjectWrapperHandle in s_referenceTrackerNativeObjectWrapperCache)
{
ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper = Unsafe.As<ReferenceTrackerNativeObjectWrapper?>(weakNativeObjectWrapperHandle.Target);
Expand Down Expand Up @@ -1272,6 +1283,7 @@ internal static unsafe void WalkExternalTrackerObjects()
// Used during GC callback
internal static void DetachNonPromotedObjects()
{
// No lock needed to access s_referenceTrackerNativeObjectWrapperCache as this is during GC callback.
foreach (GCHandle weakNativeObjectWrapperHandle in s_referenceTrackerNativeObjectWrapperCache)
{
ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper = Unsafe.As<ReferenceTrackerNativeObjectWrapper?>(weakNativeObjectWrapperHandle.Target);
Expand Down