|
// <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 {
private static Type s_type = Type.GetType("System.SizedReference", true, false);
private Object _sizedRef;
internal SRef(Object target) {
_sizedRef = Activator.CreateInstance(s_type,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
null,
new object[] { target },
null);
}
internal long ApproximateSize {
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
get {
object o = s_type.InvokeMember("ApproximateSize",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
null, // binder
_sizedRef, // target
null, // args
CultureInfo.InvariantCulture);
return (long)o;
}
}
//
[SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Grandfathered suppression from original caching code checkin")]
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
internal void Dispose() {
s_type.InvokeMember("Dispose",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
null, // binder
_sizedRef, // target
null, // args
CultureInfo.InvariantCulture);
}
}
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();
}
}
}
}
|