Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Refactor netfx #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clr_loader/ffi/netfx.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
typedef void* pyclr_domain;
typedef int (*entry_point)(void* buffer, int size);

void pyclr_initialize();
void* pyclr_create_appdomain(const char* name, const char* config_file);
entry_point pyclr_get_function(pyclr_domain domain, const char* assembly_path, const char* class_name, const char* function);
void pyclr_close_appdomain(pyclr_domain domain);
void pyclr_finalize();
"""
]
25 changes: 20 additions & 5 deletions clr_loader/netfx.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import atexit
from .ffi import ffi, load_netfx


_FW = None


class NetFx:
def __init__(self, name=None, config_file=None):
global _FW
if _FW is None:
_FW = load_netfx()

initialize()
self._domain = _FW.pyclr_create_appdomain(
name or ffi.NULL, config_file or ffi.NULL
)
Expand All @@ -27,3 +24,21 @@ def get_callable(self, assembly_path, typename, function):
def __del__(self):
if self._domain and _FW:
_FW.pyclr_close_appdomain(self._domain)


def initialize():
global _FW
if _FW is not None:
return

_FW = load_netfx()
_FW.pyclr_initialize()

atexit.register(_release)


def _release():
global _FW
if _FW is not None:
_FW.pyclr_finalize()
_FW = None
74 changes: 44 additions & 30 deletions netfx_loader/ClrLoader.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using NXPorts.Attributes;

namespace ClrLoader
{
public static class ClrLoader
{
delegate int EntryPoint(IntPtr buffer, int size);
static bool _initialized = false;
static List<DomainData> _domains = new List<DomainData>();

[DllExport("pyclr_initialize", CallingConvention.Cdecl)]
public static void Initialize()
{
if (!_initialized)
{
_domains.Add(new DomainData(AppDomain.CurrentDomain));
_initialized = true;
}
}

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

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

var handle = GCHandle.Alloc(domain, GCHandleType.Pinned);

Print($"Created handle {handle}");

return handle.AddrOfPinnedObject();
var domainData = new DomainData(domain);
_domains.Add(domainData);
return new IntPtr(_domains.Count - 1);
}
else
{
Expand All @@ -51,18 +58,8 @@ public static IntPtr GetFunction(
{
try
{
var domainObj = AppDomain.CurrentDomain;
if (domain != IntPtr.Zero)
{
var handle = GCHandle.FromIntPtr(domain);
domainObj = (AppDomain)handle.Target;
}

var assembly = domainObj.Load(AssemblyName.GetAssemblyName(assemblyPath));
var type = assembly.GetType(typeName, throwOnError: true);
Print($"Loaded type {type}");
var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function);

var domainData = _domains[(int)domain];
var deleg = domainData.GetEntryPoint(assemblyPath, typeName, function);
return Marshal.GetFunctionPointerForDelegate(deleg);
}
catch (Exception exc)
Expand All @@ -77,21 +74,38 @@ public static void CloseAppDomain(IntPtr domain)
{
if (domain != IntPtr.Zero)
{
var handle = GCHandle.FromIntPtr(domain);
var domainObj = (AppDomain)handle.Target;
AppDomain.Unload(domainObj);
handle.Free();
try
{
var domainData = _domains[(int)domain];
domainData.Dispose();
}
catch (Exception exc)
{
Print($"Exception in {nameof(CloseAppDomain)}: {exc.GetType().Name} {exc.Message}\n{exc.StackTrace}");
}
}
}

[DllExport("pyclr_finalize", CallingConvention.Cdecl)]
public static void Close()
{
foreach (var domainData in _domains)
{
domainData.Dispose();
}

_domains.Clear();
_initialized = false;
}

#if DEBUG
static void Print(string s)
#if DEBUG
internal static void Print(string s)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why not just use Conditional("DEBUG")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'll probably do that later, thanks for the hint :)

{
Console.WriteLine(s);
}
#else
static void Print(string s) {}
#endif
#else
internal static void Print(string s) { }
#endif
}

}
61 changes: 61 additions & 0 deletions netfx_loader/DomainData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Reflection;

namespace ClrLoader
{
using static ClrLoader;

class DomainData : IDisposable
{
public delegate int EntryPoint(IntPtr buffer, int size);

bool _disposed = false;

public AppDomain Domain { get; }
public Dictionary<(string, string, string), EntryPoint> _delegates;

public DomainData(AppDomain domain)
{
Domain = domain;
_delegates = new Dictionary<(string, string, string), EntryPoint>();
}

public EntryPoint GetEntryPoint(string assemblyPath, string typeName, string function)
{
if (_disposed)
throw new InvalidOperationException("Domain is already disposed");

var key = (assemblyPath, typeName, function);

EntryPoint result;

if (!_delegates.TryGetValue(key, out result))
{
var assembly = Domain.Load(AssemblyName.GetAssemblyName(assemblyPath));
var type = assembly.GetType(typeName, throwOnError: true);

Print($"Loaded type {type}");
result = (EntryPoint)Delegate.CreateDelegate(typeof(EntryPoint), type, function);

_delegates[key] = result;
}

return result;
}

public void Dispose()
{
if (!_disposed)
{
_delegates.Clear();

if (Domain != AppDomain.CurrentDomain)
AppDomain.Unload(Domain);

_disposed = true;
}
}

}
}