1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// <copyright file="SRef.cs" company="Microsoft">
// Copyright (c) 2009 Microsoft Corporation. All rights reserved.
// </copyright>
using System;
using System.Globalization;
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
_sizedRef, // target
null, // args
CultureInfo.InvariantCulture);
return (long)o;
#endif
}
}
//
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Grandfathered suppression from original caching code checkin")]
[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();
}
}
}
}
|