diff --git a/pythonnet/__init__.py b/pythonnet/__init__.py index 692fd5700..4f162dcd5 100644 --- a/pythonnet/__init__.py +++ b/pythonnet/__init__.py @@ -63,7 +63,7 @@ def unload(): global _RUNTIME if _LOADER_ASSEMBLY is not None: func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Shutdown"] - if func(b"") != 0: + if func(b"full_shutdown") != 0: raise RuntimeError("Failed to call Python.NET shutdown") if _RUNTIME is not None: diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 8b96a96da..f9edfdc76 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -354,20 +354,16 @@ public static IntPtr tp_repr(IntPtr ob) public static void tp_dealloc(IntPtr ob) { ManagedType self = GetManagedObject(ob); - tp_clear(ob); - Runtime.PyObject_GC_UnTrack(self.pyHandle); - Runtime.PyObject_GC_Del(self.pyHandle); + RemoveObjectDict(ob); + Runtime.Py_CLEAR(ref self.tpHandle); + Runtime.PyObject_GC_UnTrack(ob); + Runtime.PyObject_GC_Del(ob); self.FreeGCHandle(); } public static int tp_clear(IntPtr ob) { - ManagedType self = GetManagedObject(ob); - if (!self.IsTypeObject()) - { - ClearObjectDict(ob); - } - self.tpHandle = IntPtr.Zero; + ClearObjectDict(ob); return 0; } diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 1ee06e682..5cad4bd69 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using System.Security; using System.Linq; +using System.Diagnostics; namespace Python.Runtime { @@ -270,7 +271,7 @@ private static void InitClassBase(Type type, ClassBase impl) // Finally, initialize the class __dict__ and return the object. var dict = new BorrowedReference(Marshal.ReadIntPtr(tp, TypeOffset.tp_dict)); - + Debug.Assert(!dict.IsNull); if (impl.dotNetMembers == null) { diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs index a5f0f1219..e6c95ecaa 100644 --- a/src/runtime/extensiontype.cs +++ b/src/runtime/extensiontype.cs @@ -55,7 +55,7 @@ void SetupGc () /// public static void FinalizeObject(ManagedType self) { - ClearObjectDict(self.pyHandle); + RemoveObjectDict(self.pyHandle); Runtime.PyObject_GC_Del(self.pyHandle); // Not necessary for decref of `tpHandle`. self.FreeGCHandle(); diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index 09e8a3be2..07b57858e 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -243,6 +243,16 @@ protected virtual void OnSave(InterDomainContext context) { } protected virtual void OnLoad(InterDomainContext context) { } protected static void ClearObjectDict(IntPtr ob) + { + IntPtr dict = GetObjectDict(ob); + if (dict == IntPtr.Zero) + { + return; + } + Runtime.PyDict_Clear(dict); + } + + protected static void RemoveObjectDict(IntPtr ob) { IntPtr dict = GetObjectDict(ob); if (dict == IntPtr.Zero) diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index 36b406c7b..babb06cdf 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -304,6 +304,12 @@ public static void tp_dealloc(IntPtr tp) NativeCall.Void_Call_1(op, tp); } + public static int tp_clear(IntPtr ob) + { + ClearObjectDict(ob); + return 0; + } + private static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType) { var cb = GetManagedObject(tp) as ClassBase; diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs index 37c01f5c5..630f286da 100644 --- a/src/runtime/methodobject.cs +++ b/src/runtime/methodobject.cs @@ -217,7 +217,7 @@ public static IntPtr tp_repr(IntPtr ob) { var self = (MethodObject)GetManagedObject(ob); self.ClearMembers(); - ClearObjectDict(ob); + RemoveObjectDict(ob); self.Dealloc(); } diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index ec7f5e446..ce0870d43 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -503,15 +503,19 @@ private static void PyDictTryDelItem(BorrowedReference dict, string key) private static void MoveClrInstancesOnwershipToPython() { var objs = ManagedType.GetManagedObjects(); - var copyObjs = objs.ToArray(); - foreach (var entry in copyObjs) + var copyObjs = new KeyValuePair[objs.Count]; { - ManagedType obj = entry.Key; - if (!objs.ContainsKey(obj)) + int i = 0; + foreach (var entry in objs) { - System.Diagnostics.Debug.Assert(obj.gcHandle == default); - continue; + ManagedType obj = entry.Key; + XIncref(obj.pyHandle); + copyObjs[i++] = entry; } + } + foreach (var entry in copyObjs) + { + ManagedType obj = entry.Key; if (entry.Value == ManagedType.TrackTypes.Extension) { obj.CallTypeClear(); @@ -522,11 +526,21 @@ private static void MoveClrInstancesOnwershipToPython() PyObject_GC_Track(obj.pyHandle); } } - if (obj.gcHandle.IsAllocated) + } + foreach (var entry in copyObjs) + { + ManagedType obj = entry.Key; + if (!objs.ContainsKey(obj)) + { + System.Diagnostics.Debug.Assert(obj.gcHandle == default); + continue; + } + if (obj.RefCount > 1) { - obj.gcHandle.Free(); + obj.FreeGCHandle(); + Marshal.WriteIntPtr(obj.pyHandle, ObjectOffset.magic(obj.tpHandle), IntPtr.Zero); } - obj.gcHandle = default; + XDecref(obj.pyHandle); } ManagedType.ClearTrackedObjects(); }