-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathDomainData.cs
More file actions
122 lines (101 loc) · 4.48 KB
/
DomainData.cs
File metadata and controls
122 lines (101 loc) · 4.48 KB
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
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
namespace ClrLoader
{
using static ClrLoader;
public static class DomainSetup
{
public delegate int EntryPoint(IntPtr buffer, int size);
public static void StoreFunctorFromDomainData()
{
var domain = AppDomain.CurrentDomain;
var assemblyPath = (string)domain.GetData("_assemblyPath");
var typeName = (string)domain.GetData("_typeName");
var function = (string)domain.GetData("_function");
var deleg = GetDelegate(domain, assemblyPath, typeName, function);
var functor = Marshal.GetFunctionPointerForDelegate(deleg);
domain.SetData("_thisDelegate", deleg);
domain.SetData("_thisFunctor", functor);
}
private static Delegate GetDelegate(AppDomain domain, string assemblyPath, string typeName, string function)
{
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
var assembly = domain.Load(assemblyName);
var type = assembly.GetType(typeName, throwOnError: true);
var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function);
return deleg;
}
}
class DomainData : IDisposable
{
bool _disposed = false;
public AppDomain Domain { get; }
public Dictionary<Tuple<string, string, string>, IntPtr> _functors;
public HashSet<string> _resolvedAssemblies;
public DomainData(AppDomain domain)
{
Domain = domain;
_functors = new Dictionary<Tuple<string, string, string>, IntPtr>();
_resolvedAssemblies = new HashSet<string>();
}
private void installResolver(string assemblyPath)
{
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name;
if (_resolvedAssemblies.Contains(assemblyName))
return;
_resolvedAssemblies.Add(assemblyName);
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
if (args.Name.Contains(assemblyName))
return Assembly.LoadFrom(assemblyPath);
return null;
};
}
private static readonly object _lockObj = new object();
public IntPtr GetFunctor(string assemblyPath, string typeName, string function)
{
if (_disposed)
throw new InvalidOperationException("Domain is already disposed");
// neither the domain data nor the _functors dictionary is threadsafe
lock (_lockObj)
{
installResolver(assemblyPath);
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name;
var key = Tuple.Create(assemblyName, typeName, function);
IntPtr result;
if (!_functors.TryGetValue(key, out result))
{
Domain.SetData("_assemblyPath", assemblyPath);
Domain.SetData("_typeName", typeName);
Domain.SetData("_function", function);
Domain.DoCallBack(new CrossAppDomainDelegate(DomainSetup.StoreFunctorFromDomainData));
result = (IntPtr)Domain.GetData("_thisFunctor");
if (result == IntPtr.Zero)
throw new Exception($"Unable to get functor for {assemblyName}, {typeName}, {function}");
// set inputs to StoreFunctorFromDomainData to null.
// (There's no method to explicitly clear domain data)
Domain.SetData("_assemblyPath", null);
Domain.SetData("_typeName", null);
Domain.SetData("_function", null);
// the result has to remain in the domain data because we don't know when the
// client of pyclr_get_function will actually invoke the functor, and if we
// remove it from the domain data after returning it may get collected too early.
_functors[key] = result;
}
return result;
}
}
public void Dispose()
{
if (!_disposed)
{
_functors.Clear();
if (Domain != AppDomain.CurrentDomain)
AppDomain.Unload(Domain);
_disposed = true;
}
}
}
}