|
|
@@ -1,4 +1,5 @@
|
|
|
using System;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
namespace AtomicEngine
|
|
|
@@ -12,15 +13,20 @@ namespace AtomicEngine
|
|
|
|
|
|
// can we detect a native class?
|
|
|
|
|
|
+ // we shouldn't go off IntPtr here, as a pointer could be reused native before recycles
|
|
|
+
|
|
|
static class NativeCore
|
|
|
{
|
|
|
// given an existing instance classID, construct the managed instance, with downcast support (ask for Component, get StaticModel for example)
|
|
|
public static Dictionary<IntPtr, Func<IntPtr, RefCounted>> nativeClassIDToManagedConstructor = new Dictionary<IntPtr, Func<IntPtr, RefCounted>>();
|
|
|
|
|
|
- public static Dictionary<IntPtr, WeakReference> nativeLookup = new Dictionary<IntPtr, WeakReference> ();
|
|
|
-
|
|
|
+ // native engine types, instances of these types can be trivially recreated managed side
|
|
|
private static Dictionary<Type, Type> nativeTypes = new Dictionary<Type, Type> ();
|
|
|
|
|
|
+ // RefID -> WeakReference of managed instance
|
|
|
+ public static Dictionary<uint, WeakReference> nativeLookup = new Dictionary<uint, WeakReference> ();
|
|
|
+
|
|
|
+
|
|
|
public static bool GetNativeType (Type type)
|
|
|
{
|
|
|
return nativeTypes.ContainsKey (type);
|
|
|
@@ -33,17 +39,20 @@ namespace AtomicEngine
|
|
|
|
|
|
public static IntPtr RegisterNative (IntPtr native, RefCounted r)
|
|
|
{
|
|
|
+ r.nativeInstance = native;
|
|
|
+
|
|
|
var w = new WeakReference (r);
|
|
|
- NativeCore.nativeLookup [native] = w;
|
|
|
- RefCounted._AddRef (native);
|
|
|
+ NativeCore.nativeLookup [r.RefID] = w;
|
|
|
+ r.AddRef();
|
|
|
+
|
|
|
return native;
|
|
|
}
|
|
|
|
|
|
public static void ReleaseExpiredNativeReferences()
|
|
|
{
|
|
|
- List<IntPtr> released = new List<IntPtr> ();
|
|
|
+ List<uint> released = new List<uint> ();
|
|
|
|
|
|
- foreach(KeyValuePair<IntPtr, WeakReference> entry in nativeLookup)
|
|
|
+ foreach(KeyValuePair<uint, WeakReference> entry in nativeLookup)
|
|
|
{
|
|
|
|
|
|
if (entry.Value.Target == null || !entry.Value.IsAlive) {
|
|
|
@@ -55,9 +64,11 @@ namespace AtomicEngine
|
|
|
|
|
|
}
|
|
|
|
|
|
- foreach (IntPtr native in released) {
|
|
|
- RefCounted._ReleaseRef(native);
|
|
|
- nativeLookup.Remove (native);
|
|
|
+ foreach (uint id in released) {
|
|
|
+
|
|
|
+ // use safe release
|
|
|
+ RefCounted.SafeReleaseRef (id);
|
|
|
+ nativeLookup.Remove (id);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -68,10 +79,13 @@ namespace AtomicEngine
|
|
|
if (native == IntPtr.Zero)
|
|
|
return null;
|
|
|
|
|
|
+ // instance id
|
|
|
+ uint id = csb_Atomic_RefCounted_GetRefID (native);
|
|
|
+
|
|
|
WeakReference w;
|
|
|
|
|
|
// first see if we're already available
|
|
|
- if (nativeLookup.TryGetValue (native, out w)) {
|
|
|
+ if (nativeLookup.TryGetValue (id, out w)) {
|
|
|
|
|
|
if (w.IsAlive) {
|
|
|
|
|
|
@@ -81,23 +95,29 @@ namespace AtomicEngine
|
|
|
} else {
|
|
|
|
|
|
// we were seen before, but have since been GC'd, remove!
|
|
|
- nativeLookup.Remove (native);
|
|
|
+ nativeLookup.Remove (id);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- IntPtr classID = RefCounted.csb_RefCounted_GetClassID (native);
|
|
|
+ IntPtr classID = RefCounted.csb_Atomic_RefCounted_GetClassID (native);
|
|
|
|
|
|
// and store, with downcast support for instance Component -> StaticModel
|
|
|
- // we never want to hit this path for scripted natives
|
|
|
- w = new WeakReference (nativeClassIDToManagedConstructor[classID](native));
|
|
|
- NativeCore.nativeLookup [native] = w;
|
|
|
+ // we never want to hit this path for script inherited natives
|
|
|
+
|
|
|
+ RefCounted r = nativeClassIDToManagedConstructor[classID](native);
|
|
|
+ w = new WeakReference (r);
|
|
|
+ NativeCore.nativeLookup [id] = w;
|
|
|
|
|
|
// store a ref, so native side will not be released while we still have a reference in managed code
|
|
|
- RefCounted._AddRef (native);
|
|
|
+ r.AddRef();
|
|
|
|
|
|
- return (T) w.Target;
|
|
|
+ return (T) r;
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ [DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
|
+ private static extern uint csb_Atomic_RefCounted_GetRefID(IntPtr self);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
}
|