You've already forked linux-packaging-mono
Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
This commit is contained in:
parent
ee1447783b
commit
94b2861243
@@ -27,7 +27,7 @@ namespace System.Runtime.Caching {
|
||||
private long[] _cacheSizeSamples;
|
||||
private DateTime[] _cacheSizeSampleTimes;
|
||||
private int _idx;
|
||||
private SRef _sizedRef;
|
||||
private SRefMultiple _sizedRefMultiple;
|
||||
private int _gen2Count;
|
||||
private long _memoryLimit;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace System.Runtime.Caching {
|
||||
private void InitDisposableMembers(int cacheMemoryLimitMegabytes) {
|
||||
bool dispose = true;
|
||||
try {
|
||||
_sizedRef = new SRef(_memoryCache);
|
||||
_sizedRefMultiple = new SRefMultiple(_memoryCache.AllSRefTargets);
|
||||
SetLimit(cacheMemoryLimitMegabytes);
|
||||
InitHistory();
|
||||
dispose = false;
|
||||
@@ -112,8 +112,8 @@ namespace System.Runtime.Caching {
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
SRef sref = _sizedRef;
|
||||
if (sref != null && Interlocked.CompareExchange(ref _sizedRef, null, sref) == sref) {
|
||||
SRefMultiple sref = _sizedRefMultiple;
|
||||
if (sref != null && Interlocked.CompareExchange(ref _sizedRefMultiple, null, sref) == sref) {
|
||||
sref.Dispose();
|
||||
}
|
||||
IMemoryCacheManager memoryCacheManager = s_memoryCacheManager;
|
||||
@@ -139,7 +139,7 @@ namespace System.Runtime.Caching {
|
||||
// This update must happen, otherwise the CacheManager won't
|
||||
// know the total cache size.
|
||||
int gen2Count = GC.CollectionCount(2);
|
||||
SRef sref = _sizedRef;
|
||||
SRefMultiple sref = _sizedRefMultiple;
|
||||
if (gen2Count != _gen2Count && sref != null) {
|
||||
// update _gen2Count
|
||||
_gen2Count = gen2Count;
|
||||
|
@@ -27,9 +27,8 @@ namespace System.Runtime.Caching {
|
||||
private static object s_initLock = new object();
|
||||
private static MemoryCache s_defaultCache;
|
||||
private static CacheEntryRemovedCallback s_sentinelRemovedCallback = new CacheEntryRemovedCallback(SentinelEntry.OnCacheEntryRemovedCallback);
|
||||
private MemoryCacheStore[] _stores;
|
||||
private GCHandleRef<MemoryCacheStore>[] _storeRefs;
|
||||
private int _storeCount;
|
||||
private int _storeMask;
|
||||
private int _disposed;
|
||||
private MemoryCacheStatistics _stats;
|
||||
private string _name;
|
||||
@@ -150,8 +149,18 @@ namespace System.Runtime.Caching {
|
||||
if (hashCode < 0) {
|
||||
hashCode = (hashCode == Int32.MinValue) ? 0 : -hashCode;
|
||||
}
|
||||
int idx = hashCode & _storeMask;
|
||||
return _stores[idx];
|
||||
int idx = hashCode % _storeCount;
|
||||
return _storeRefs[idx].Target;
|
||||
}
|
||||
|
||||
internal object[] AllSRefTargets {
|
||||
get {
|
||||
var allStores = new MemoryCacheStore[_storeCount];
|
||||
for (int i = 0; i < _storeCount; i++) {
|
||||
allStores[i] = _storeRefs[i].Target;
|
||||
}
|
||||
return allStores;
|
||||
}
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
@@ -166,8 +175,8 @@ namespace System.Runtime.Caching {
|
||||
catch {
|
||||
// ignore exceptions from perf counters
|
||||
}
|
||||
for (int i = 0; i < _stores.Length; i++) {
|
||||
_stores[i] = new MemoryCacheStore(this, _perfCounters);
|
||||
for (int i = 0; i < _storeCount; i++) {
|
||||
_storeRefs[i] = new GCHandleRef<MemoryCacheStore> (new MemoryCacheStore(this, _perfCounters));
|
||||
}
|
||||
_stats = new MemoryCacheStatistics(this, config);
|
||||
AppDomain appDomain = Thread.GetDomain();
|
||||
@@ -321,8 +330,7 @@ namespace System.Runtime.Caching {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_storeMask = _storeCount - 1;
|
||||
_stores = new MemoryCacheStore[_storeCount];
|
||||
_storeRefs = new GCHandleRef<MemoryCacheStore>[_storeCount];
|
||||
InitDisposableMembers(config);
|
||||
}
|
||||
|
||||
@@ -392,10 +400,10 @@ namespace System.Runtime.Caching {
|
||||
if (_stats != null) {
|
||||
_stats.Dispose();
|
||||
}
|
||||
if (_stores != null) {
|
||||
foreach (MemoryCacheStore store in _stores) {
|
||||
if (store != null) {
|
||||
store.Dispose();
|
||||
if (_storeRefs != null) {
|
||||
foreach (var storeRef in _storeRefs) {
|
||||
if (storeRef != null) {
|
||||
storeRef.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,8 +450,8 @@ namespace System.Runtime.Caching {
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
Hashtable h = new Hashtable();
|
||||
if (!IsDisposed) {
|
||||
foreach (MemoryCacheStore store in _stores) {
|
||||
store.CopyTo(h);
|
||||
foreach (var storeRef in _storeRefs) {
|
||||
storeRef.Target.CopyTo(h);
|
||||
}
|
||||
}
|
||||
return h.GetEnumerator();
|
||||
@@ -452,8 +460,8 @@ namespace System.Runtime.Caching {
|
||||
protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
|
||||
Dictionary<string, object> h = new Dictionary<string, object>();
|
||||
if (!IsDisposed) {
|
||||
foreach (MemoryCacheStore store in _stores) {
|
||||
store.CopyTo(h);
|
||||
foreach (var storeRef in _storeRefs) {
|
||||
storeRef.Target.CopyTo(h);
|
||||
}
|
||||
}
|
||||
return h.GetEnumerator();
|
||||
@@ -471,8 +479,8 @@ namespace System.Runtime.Caching {
|
||||
}
|
||||
long trimmed = 0;
|
||||
if (_disposed == 0) {
|
||||
foreach (MemoryCacheStore store in _stores) {
|
||||
trimmed += store.TrimInternal(percent);
|
||||
foreach (var storeRef in _storeRefs) {
|
||||
trimmed += storeRef.Target.TrimInternal(percent);
|
||||
}
|
||||
}
|
||||
return trimmed;
|
||||
@@ -680,8 +688,8 @@ namespace System.Runtime.Caching {
|
||||
}
|
||||
long count = 0;
|
||||
if (!IsDisposed) {
|
||||
foreach (MemoryCacheStore store in _stores) {
|
||||
count += store.Count;
|
||||
foreach (var storeRef in _storeRefs) {
|
||||
count += storeRef.Target.Count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@@ -27,7 +27,7 @@ namespace System.Runtime.Caching {
|
||||
private int _lastTrimPercent;
|
||||
private DateTime _lastTrimTime;
|
||||
private int _pollingInterval;
|
||||
private Timer _timer;
|
||||
private GCHandleRef<Timer> _timerHandleRef;
|
||||
private Object _timerLock;
|
||||
private long _totalCountBeforeTrim;
|
||||
|
||||
@@ -44,16 +44,18 @@ namespace System.Runtime.Caching {
|
||||
private void AdjustTimer() {
|
||||
lock (_timerLock) {
|
||||
|
||||
if (_timer == null)
|
||||
if (_timerHandleRef == null)
|
||||
return;
|
||||
|
||||
Timer timer = _timerHandleRef.Target;
|
||||
|
||||
// the order of these if statements is important
|
||||
|
||||
// When above the high pressure mark, interval should be 5 seconds or less
|
||||
if (_physicalMemoryMonitor.IsAboveHighPressure() || _cacheMemoryMonitor.IsAboveHighPressure()) {
|
||||
if (_pollingInterval > MEMORYSTATUS_INTERVAL_5_SECONDS) {
|
||||
_pollingInterval = MEMORYSTATUS_INTERVAL_5_SECONDS;
|
||||
_timer.Change(_pollingInterval, _pollingInterval);
|
||||
timer.Change(_pollingInterval, _pollingInterval);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -65,7 +67,7 @@ namespace System.Runtime.Caching {
|
||||
int newPollingInterval = Math.Min(_configPollingInterval, MEMORYSTATUS_INTERVAL_30_SECONDS);
|
||||
if (_pollingInterval != newPollingInterval) {
|
||||
_pollingInterval = newPollingInterval;
|
||||
_timer.Change(_pollingInterval, _pollingInterval);
|
||||
timer.Change(_pollingInterval, _pollingInterval);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -73,7 +75,7 @@ namespace System.Runtime.Caching {
|
||||
// there is no pressure, interval should be the value from config
|
||||
if (_pollingInterval != _configPollingInterval) {
|
||||
_pollingInterval = _configPollingInterval;
|
||||
_timer.Change(_pollingInterval, _pollingInterval);
|
||||
timer.Change(_pollingInterval, _pollingInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +128,8 @@ namespace System.Runtime.Caching {
|
||||
bool dispose = true;
|
||||
try {
|
||||
_cacheMemoryMonitor = new CacheMemoryMonitor(_memoryCache, _configCacheMemoryLimitMegabytes);
|
||||
_timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
|
||||
Timer timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
|
||||
_timerHandleRef = new GCHandleRef<Timer>(timer);
|
||||
dispose = false;
|
||||
}
|
||||
finally {
|
||||
@@ -246,9 +249,9 @@ namespace System.Runtime.Caching {
|
||||
public void Dispose() {
|
||||
if (Interlocked.Exchange(ref _disposed, 1) == 0) {
|
||||
lock (_timerLock) {
|
||||
Timer timer = _timer;
|
||||
if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer) {
|
||||
timer.Dispose();
|
||||
GCHandleRef<Timer> timerHandleRef = _timerHandleRef;
|
||||
if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef) {
|
||||
timerHandleRef.Dispose();
|
||||
Dbg.Trace("MemoryCacheStats", "Stopped CacheMemoryTimers");
|
||||
}
|
||||
}
|
||||
|
@@ -7,24 +7,33 @@ using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Runtime.Caching {
|
||||
internal class SRef {
|
||||
#if !MONO
|
||||
private static Type s_type = Type.GetType("System.SizedReference", true, false);
|
||||
private Object _sizedRef;
|
||||
#endif
|
||||
|
||||
internal SRef(Object target) {
|
||||
#if !MONO
|
||||
_sizedRef = Activator.CreateInstance(s_type,
|
||||
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
|
||||
null,
|
||||
new object[] { target },
|
||||
null);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal long ApproximateSize {
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
get {
|
||||
#if MONO
|
||||
// TODO: .net uses System.SizedReference which contains approximate size after Gen 2 collection
|
||||
return 16;
|
||||
#else
|
||||
object o = s_type.InvokeMember("ApproximateSize",
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
|
||||
null, // binder
|
||||
@@ -32,6 +41,7 @@ namespace System.Runtime.Caching {
|
||||
null, // args
|
||||
CultureInfo.InvariantCulture);
|
||||
return (long)o;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +50,87 @@ namespace System.Runtime.Caching {
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
internal void Dispose() {
|
||||
#if !MONO
|
||||
s_type.InvokeMember("Dispose",
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
|
||||
null, // binder
|
||||
_sizedRef, // target
|
||||
null, // args
|
||||
CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
internal class SRefMultiple {
|
||||
private SRef[] _srefs;
|
||||
private long[] _sizes; // Getting SRef size in the debugger is extremely tedious so we keep the last read value here
|
||||
|
||||
internal SRefMultiple(object[] targets) {
|
||||
_srefs = new SRef[targets.Length];
|
||||
_sizes = new long[targets.Length];
|
||||
for (int i = 0; i < targets.Length; i++) {
|
||||
_srefs[i] = new SRef(targets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal long ApproximateSize {
|
||||
get {
|
||||
long size = 0;
|
||||
for (int i = 0; i < _srefs.Length; i++) {
|
||||
size += (_sizes[i] = _srefs[i].ApproximateSize);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose() {
|
||||
foreach (SRef s in _srefs) {
|
||||
s.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class GCHandleRef<T> : IDisposable
|
||||
where T : class, IDisposable {
|
||||
GCHandle _handle;
|
||||
T _t;
|
||||
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
public GCHandleRef(T t) {
|
||||
_handle = GCHandle.Alloc(t);
|
||||
}
|
||||
|
||||
public T Target {
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
get {
|
||||
try {
|
||||
T t = (T)_handle.Target;
|
||||
if (t != null) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
catch (InvalidOperationException) {
|
||||
// use the normal reference instead of throwing an exception when _handle is already freed
|
||||
}
|
||||
return _t;
|
||||
}
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
|
||||
public void Dispose() {
|
||||
Target.Dispose();
|
||||
// Safe to call Dispose more than once but not thread-safe
|
||||
if (_handle.IsAllocated) {
|
||||
// We must free the GC handle to avoid leaks.
|
||||
// However after _handle is freed we no longer have access to its Target
|
||||
// which will cause AVs and various race conditions under stress.
|
||||
// We revert to using normal references after disposing the GC handle
|
||||
_t = (T)_handle.Target;
|
||||
_handle.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user