File: SRef.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (136 lines) | stat: -rw-r--r-- 4,867 bytes parent folder | download | duplicates (6)
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();
            }
        }
    }
}