Skip to content

Commit 969f237

Browse files
committed
Refactor ownership in .NET Framework loader
1 parent e512c7a commit 969f237

File tree

2 files changed

+105
-30
lines changed

2 files changed

+105
-30
lines changed

netfx_loader/ClrLoader.cs

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
using System;
2-
using System.Diagnostics;
3-
using System.Globalization;
2+
using System.Collections.Generic;
43
using System.IO;
5-
using System.Reflection;
64
using System.Runtime.InteropServices;
75
using NXPorts.Attributes;
86

97
namespace ClrLoader
108
{
119
public static class ClrLoader
1210
{
13-
delegate int EntryPoint(IntPtr buffer, int size);
11+
static bool _initialized = false;
12+
static List<DomainData> _domains = new List<DomainData>();
13+
14+
[DllExport("pyclr_initialize", CallingConvention.Cdecl)]
15+
public static void Initialize()
16+
{
17+
if (!_initialized)
18+
{
19+
_domains.Add(new DomainData(AppDomain.CurrentDomain));
20+
_initialized = true;
21+
}
22+
}
1423

1524
[DllExport("pyclr_create_appdomain", CallingConvention.Cdecl)]
1625
public static IntPtr CreateAppDomain(
@@ -29,11 +38,9 @@ public static IntPtr CreateAppDomain(
2938

3039
Print($"Located domain {domain}");
3140

32-
var handle = GCHandle.Alloc(domain, GCHandleType.Pinned);
33-
34-
Print($"Created handle {handle}");
35-
36-
return handle.AddrOfPinnedObject();
41+
var domainData = new DomainData(domain);
42+
_domains.Add(domainData);
43+
return new IntPtr(_domains.Count - 1);
3744
}
3845
else
3946
{
@@ -51,18 +58,8 @@ public static IntPtr GetFunction(
5158
{
5259
try
5360
{
54-
var domainObj = AppDomain.CurrentDomain;
55-
if (domain != IntPtr.Zero)
56-
{
57-
var handle = GCHandle.FromIntPtr(domain);
58-
domainObj = (AppDomain)handle.Target;
59-
}
60-
61-
var assembly = domainObj.Load(AssemblyName.GetAssemblyName(assemblyPath));
62-
var type = assembly.GetType(typeName, throwOnError: true);
63-
Print($"Loaded type {type}");
64-
var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function);
65-
61+
var domainData = _domains[(int)domain];
62+
var deleg = domainData.GetEntryPoint(assemblyPath, typeName, function);
6663
return Marshal.GetFunctionPointerForDelegate(deleg);
6764
}
6865
catch (Exception exc)
@@ -77,21 +74,38 @@ public static void CloseAppDomain(IntPtr domain)
7774
{
7875
if (domain != IntPtr.Zero)
7976
{
80-
var handle = GCHandle.FromIntPtr(domain);
81-
var domainObj = (AppDomain)handle.Target;
82-
AppDomain.Unload(domainObj);
83-
handle.Free();
77+
try
78+
{
79+
var domainData = _domains[(int)domain];
80+
domainData.Dispose();
81+
}
82+
catch (Exception exc)
83+
{
84+
Print($"Exception in {nameof(CloseAppDomain)}: {exc.GetType().Name} {exc.Message}\n{exc.StackTrace}");
85+
}
86+
}
87+
}
88+
89+
[DllExport("pyclr_finalize", CallingConvention.Cdecl)]
90+
public static void Close()
91+
{
92+
foreach (var domainData in _domains)
93+
{
94+
domainData.Dispose();
8495
}
96+
97+
_domains.Clear();
98+
_initialized = false;
8599
}
86100

87-
#if DEBUG
88-
static void Print(string s)
101+
#if DEBUG
102+
internal static void Print(string s)
89103
{
90104
Console.WriteLine(s);
91105
}
92-
#else
93-
static void Print(string s) {}
94-
#endif
106+
#else
107+
internal static void Print(string s) { }
108+
#endif
95109
}
96110

97111
}

netfx_loader/DomainData.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
5+
namespace ClrLoader
6+
{
7+
using static ClrLoader;
8+
9+
class DomainData : IDisposable
10+
{
11+
public delegate int EntryPoint(IntPtr buffer, int size);
12+
13+
bool _disposed = false;
14+
15+
public AppDomain Domain { get; }
16+
public Dictionary<(string, string, string), EntryPoint> _delegates;
17+
18+
public DomainData(AppDomain domain)
19+
{
20+
Domain = domain;
21+
_delegates = new Dictionary<(string, string, string), EntryPoint>();
22+
}
23+
24+
public EntryPoint GetEntryPoint(string assemblyPath, string typeName, string function)
25+
{
26+
if (_disposed)
27+
throw new InvalidOperationException("Domain is already disposed");
28+
29+
var key = (assemblyPath, typeName, function);
30+
31+
EntryPoint result;
32+
33+
if (!_delegates.TryGetValue(key, out result))
34+
{
35+
var assembly = Domain.Load(AssemblyName.GetAssemblyName(assemblyPath));
36+
var type = assembly.GetType(typeName, throwOnError: true);
37+
38+
Print($"Loaded type {type}");
39+
result = (EntryPoint)Delegate.CreateDelegate(typeof(EntryPoint), type, function);
40+
41+
_delegates[key] = result;
42+
}
43+
44+
return result;
45+
}
46+
47+
public void Dispose()
48+
{
49+
if (!_disposed)
50+
{
51+
_delegates.Clear();
52+
53+
if (Domain != AppDomain.CurrentDomain)
54+
AppDomain.Unload(Domain);
55+
56+
_disposed = true;
57+
}
58+
}
59+
60+
}
61+
}

0 commit comments

Comments
 (0)