Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);netcoreapp3.1-windows;netcoreapp3.1;netstandard2.0-windows;netstandard2.0</TargetFrameworks>
<IsPackable>true</IsPackable>
<!-- If you enable GeneratePackageOnBuild for this package and bump ServicingVersion, make sure to also bump ServicingVersion in Microsoft.Windows.Compatibility.csproj once for the next release. -->
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<ServicingVersion>0</ServicingVersion>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<ServicingVersion>1</ServicingVersion>
<AddNETFrameworkPlaceholderFileToPackage>true</AddNETFrameworkPlaceholderFileToPackage>
<AddXamarinPlaceholderFilesToPackage>true</AddXamarinPlaceholderFilesToPackage>
<AddNETFrameworkAssemblyReferenceToPackage>true</AddNETFrameworkAssemblyReferenceToPackage>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class MemoryCache : ObjectCache, IEnumerable, IDisposable
private bool _useMemoryCacheManager = true;
private EventHandler _onAppDomainUnload;
private UnhandledExceptionEventHandler _onUnhandledException;
private int _inUnhandledExceptionHandler;
#if NET5_0_OR_GREATER
[UnsupportedOSPlatformGuard("browser")]
private static bool _countersSupported => !OperatingSystem.IsBrowser();
Expand Down Expand Up @@ -240,14 +241,19 @@ private void OnAppDomainUnload(object unusedObject, EventArgs unusedEventArgs)
Dispose();
}

internal bool InUnhandledExceptionHandler => _inUnhandledExceptionHandler > 0;
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
Interlocked.Increment(ref _inUnhandledExceptionHandler);

// if the CLR is terminating, dispose the cache.
// This will dispose the perf counters
if (eventArgs.IsTerminating)
{
Dispose();
}

Interlocked.Decrement(ref _inUnhandledExceptionHandler);
}

private void ValidatePolicy(CacheItemPolicy policy)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,19 @@ public void Dispose()
GCHandleRef<Timer> timerHandleRef = _timerHandleRef;
if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef)
{
timerHandleRef.Dispose();
Dbg.Trace("MemoryCacheStats", "Stopped CacheMemoryTimers");
// If inside an unhandled exception handler, Timers may be succeptible to deadlocks. Use a safer approach.
if (_memoryCache.InUnhandledExceptionHandler)
{
// This does not stop/dispose the timer. But the callback on the timer is protected by _disposed, which we have already
// set above.
timerHandleRef.FreeHandle();
Dbg.Trace("MemoryCacheStats", "Freed CacheMemoryTimers");
}
else
{
timerHandleRef.Dispose();
Dbg.Trace("MemoryCacheStats", "Stopped CacheMemoryTimers");
}
}
}
while (_inCacheManagerThread != 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public T Target
public void Dispose()
{
Target.Dispose();
FreeHandle();
}

internal void FreeHandle()
{
// Safe to call Dispose more than once but not thread-safe
if (_handle.IsAllocated)
{
Expand Down