8000 Add soft shutdown · pythonnet/pythonnet@4e19a4f · GitHub
[go: up one dir, main page]

Skip to content

Commit 4e19a4f

Browse files
committed
Add soft shutdown
1 parent 1bcbeb5 commit 4e19a4f

20 files changed

+1079
-152
lines changed

src/embed_tests/TestDomainReload.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static void DomainReloadAndGC()
5757
RunAssemblyAndUnload(pythonRunner1, "test1");
5858

5959
// Verify that python is not initialized even though we ran it.
60-
Assert.That(Runtime.Runtime.Py_IsInitialized(), Is.Zero);
60+
//Assert.That(Runtime.Runtime.Py_IsInitialized(), Is.Zero);
6161

6262
// This caused a crash because objects allocated in pythonRunner1
6363
// still existed in memory, but the code to do python GC on those
@@ -83,6 +83,7 @@ public static void RunPython() {
8383
AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
8484
string name = AppDomain.CurrentDomain.FriendlyName;
8585
Console.WriteLine(string.Format(""[{0} in .NET] In PythonRunner.RunPython"", name));
86+
//PythonEngine.Initialize(softShutdown: true);
8687
using (Py.GIL()) {
8788
try {
8889
var pyScript = string.Format(""import clr\n""

src/runtime/classbase.cs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Diagnostics;
34
using System.Runtime.InteropServices;
45

56
namespace Python.Runtime
@@ -253,15 +254,48 @@ public static IntPtr tp_str(IntPtr ob)
253254
public static void tp_dealloc(IntPtr ob)
254255
{
255256
ManagedType self = GetManagedObject(ob);
256-
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob));
257-
if (dict != IntPtr.Zero)
257+
if (self.pyHandle != self.tpHandle)
258258
{
259-
Runtime.XDecref(dict);
259+
ClearObjectDict(ob);
260260
}
261261
Runtime.PyObject_GC_UnTrack(self.pyHandle);
262262
Runtime.PyObject_GC_Del(self.pyHandle);
263263
Runtime.XDecref(self.tpHandle);
264-
self.gcHandle.Free();
264+
self.FreeGCHandle();
265+
}
266+
267+
public static int tp_clear(IntPtr ob)
268+
{
269+
ManagedType self = GetManagedObject(ob);
270+
if (self.pyHandle != self.tpHandle)
271+
{
272+
ClearObjectDict(ob);
273+
}
274+
Runtime.XDecref(self.tpHandle);
275+
self.tpHandle = IntPtr.Zero;
276+
self.FreeGCHandle();
277+
return 0;
278+
}
279+
280+
private static IntPtr GetObjectDict(IntPtr ob)
281+
{
282+
return Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob));
283+
}
284+
285+
private static void SetObjectDict(IntPtr ob, IntPtr value)
286+
{
287+
Marshal.WriteIntPtr(ob, ObjectOffset.DictOffset(ob), value);
288+
}
289+
290+
private static void ClearObjectDict(IntPtr ob)
291+
{
292+
IntPtr dict = GetObjectDict(ob);
293+
if (dict == IntPtr.Zero)
294+
{
295+
return;
296+
}
297+
SetObjectDict(ob, IntPtr.Zero);
298+
Runtime.XDecref(dict);
265299
}
266300
}
267301
}

src/runtime/classmanager.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Reflection;
55
using System.Runtime.InteropServices;
66
using System.Security;
7+
using System.Linq;
78

89
namespace Python.Runtime
910
{
@@ -26,7 +27,6 @@ private ClassManager()
2627

2728
static ClassManager()
2829
{
29-
cache = new Dictionary<Type, ClassBase>(128);
3030
// SEE: https://msdn.microsoft.com/en-us/library/96b1ayy4(v=vs.100).aspx
3131
// ""All delegates inherit from MulticastDelegate, which inherits from Delegate.""
3232
// Was Delegate, which caused a null MethodInfo returned from GetMethode("Invoke")
@@ -39,6 +39,49 @@ public static void Reset()
3939
cache = new Dictionary<Type, ClassBase>(128);
4040
}
4141

42+
public static IList<ClassBase> GetManagedTypes()
43+
{
44+
return cache.Values.ToArray(); // Make a copy.
45+
}
46+
47+
internal static void RemoveClasses()
48+
{
49+
var visited = new HashSet<IntPtr>();
50+
var visitedHandle = GCHandle.Alloc(visited);
51+
var visitedPtr = (IntPtr)visitedHandle;
52+
try
53+
{
54+
foreach (var cls in cache.Values)
55+
{
56+
cls.TypeTraverse(OnVisit, visitedPtr);
57+
// XXX: Force release some resouces.
58+
cls.TypeClear();
59+
//Runtime.XDecref(cls.pyHandle);
60+
}
61+
}
62+
finally
63+
{
64+
visitedHandle.Free();
65+
}
66+
}
67+
68+
private static int OnVisit(IntPtr ob, IntPtr arg)
69+
{
70+
var visited = (HashSet<IntPtr>)GCHandle.FromIntPtr(arg).Target;
71+
if (visited.Contains(ob))
72+
{
73+
return 0;
74+
}
75+
visited.Add(ob);
76+
var clrObj = ManagedType.GetManagedObject(ob);
77+
if (clrObj != null)
78+
{
79+
clrObj.TypeTraverse(OnVisit, arg);
80+
clrObj.TypeClear();
81+
}
82+
return 0;
83+
}
84+
4285
/// <summary>
4386
/// Return the ClassBase-derived instance that implements a particular
4487
/// reflected managed type, creating it if it doesn't yet exist.
@@ -134,7 +177,6 @@ private static void InitClassBase(Type type, ClassBase impl)
134177

135178

136179
IntPtr tp = TypeManager.GetTypeHandle(impl, type);
137-
impl.tpHandle = tp;
138180

139181
// Finally, initialize the class __dict__ and return the object.
140182
IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict);
@@ -146,6 +188,9 @@ private static void InitClassBase(Type type, ClassBase impl)
146188
var item = (ManagedType)iter.Value;
147189
var name = (string)iter.Key;
148190
Runtime.PyDict_SetItemString(dict, name, item.pyHandle);
191+
// info.members are already useless
192+
Runtime.XDecref(item.pyHandle);
193+
item.pyHandle = IntPtr.Zero;
149194
}
150195

151196
// If class has constructors, generate an __doc__ attribute.

src/runtime/clrobject.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ internal CLRObject(object ob, IntPtr tp)
2222
}
2323
}
2424

25-
GCHandle gc = GCHandle.Alloc(this);
25+
GCHandle gc = AllocGCHandle();
2626
Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
2727
tpHandle = tp;
2828
pyHandle = py;
29-
gcHandle = gc;
3029
inst = ob;
3130

3231
// Fix the BaseException args (and __cause__ in case of Python 3)

src/runtime/constructorbinding.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,17 @@ public static IntPtr tp_repr(IntPtr ob)
147147
Runtime.XDecref(self.pyTypeHndl);
148148
ExtensionType.FinalizeObject(self);
149149
}
150+
151+
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
152+
{
153+
var self = (ConstructorBinding)GetManagedObject(ob);
154+
int res = PyVisit(self.pyTypeHndl, visit, arg);
155+
if (res != 0) return res;
156+
157+
res = PyVisit(self.repr, visit, arg);
158+
if (res != 0) return res;
159+
return 0;
160+
}
150161
}
151162

152163
/// <summary>
@@ -233,5 +244,16 @@ public static IntPtr tp_repr(IntPtr ob)
233244
Runtime.XDecref(self.pyTypeHndl);
234245
FinalizeObject(self);
235246
}
247+
248+
public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
249+
{
250+
var self = (BoundContructor)GetManagedObject(ob);
251+
int res = PyVisit(self.pyTypeHndl, visit, arg);
252+
if (res != 0) return res;
253+
254+
res = PyVisit(self.repr, visit, arg);
255+
if (res != 0) return res;
256+
return 0;
257+
}
236258
}
237259
}

src/runtime/extensiontype.cs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public ExtensionType()
2828

2929
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
3030

31-
GCHandle gc = GCHandle.Alloc(this);
31+
GCHandle gc = AllocGCHandle();
3232
Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
3333

3434
// We have to support gc because the type machinery makes it very
@@ -40,7 +40,6 @@ public ExtensionType()
4040

4141
tpHandle = tp;
4242
pyHandle = py;
43-
gcHandle = gc;
4443
}
4544

4645

@@ -51,7 +50,7 @@ public static void FinalizeObject(ManagedType self)
5150
{
5251
Runtime.PyObject_GC_Del(self.pyHandle);
5352
Runtime.XDecref(self.tpHandle);
54-
self.gcHandle.Free();
53+
self.FreeGCHandle();
5554
}
5655

5756

@@ -91,5 +90,21 @@ public static void tp_dealloc(IntPtr ob)
9190
ManagedType self = GetManagedObject(ob);
9291
FinalizeObject(self);
9392
}
93+
94+
public static int tp_clear(IntPtr ob)
95+
{
96+
ManagedType self = GetManagedObject(ob);
97+
Runtime.XDecref(self.tpHandle);
98+
self.FreeGCHandle();
99+
return 0;
100+
}
101+
102+
//public static int tp_traverse(IntPtr ob, IntPtr visit, IntPtr arg)
103+
//{
104+
// ManagedType self = GetManagedObject(ob);
105+
// int res = PyVisit(self.tpHandle, visit, arg);
106+
// if (res != 0) return res;
107+
// return 0;
108+
//}
94109
}
95110
}

src/runtime/fieldobject.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
5555
try
5656
{
5757
var co = (CLRObject)GetManagedObject(ob);
58+
if (co == null)
59+
{
60+
Exceptions.SetError(Exceptions.TypeError, "instance is not a clr object");
61+
return IntPtr.Zero;
62+
}
5863
result = info.GetValue(co.inst);
5964
return Converter.ToPython(result, info.FieldType);
6065
}
@@ -115,6 +120,11 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp)
115120
if (!is_static)
116121
{
117122
var co = (CLRObject)GetManagedObject(ob);
123+
if (co == null)
124+
{
125+
Exceptions.SetError(Exceptions.TypeError, "instance is not a clr object");
126+
return -1;
127+
}
118128
info.SetValue(co.inst, newval);
119129
}
120130
else

src/runtime/genericutil.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ private GenericUtil()
1616
{
1717
}
1818

19-
static GenericUtil()
20-
{
21-
mapping = new Dictionary<string, Dictionary<string, List<string>>>();
22-
}
23-
2419
public static void Reset()
2520
{
2621
mapping = new Dictionary<string, Dictionary<string, List<string>>>();

src/runtime/importhook.cs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,29 @@ internal static void Initialize()
7272
/// </summary>
7373
internal static void Shutdown()
7474
{
75-
if (Runtime.Py_IsInitialized() != 0)
75+
if (Runtime.Py_IsInitialized() == 0)
7676
{
77-
Runtime.XDecref(py_clr_module);
78-
Runtime.XDecref(root.pyHandle);
79-
Runtime.XDecref(py_import);
77+
return;
8078
}
79+
IntPtr dict = Runtime.PyImport_GetModuleDict();
80+
IntPtr mod = Runtime.IsPython3 ?
81+
Runtime.PyImport_ImportModule("builtins")
82+
: Runtime.PyDict_GetItemString(dict, "__builtin__");
83+
Runtime.PyObject_SetAttrString(mod, "__import__", py_import);
84+
85+
Runtime.XDecref(py_clr_module);
86+
py_clr_module = IntPtr.Zero;
87+
88+
Runtime.XDecref(root.pyHandle);
89+
root = null;
90+
91+
hook.Dispose();
92+
hook = null;
93+
94+
Runtime.XDecref(py_import);
95+
py_import = IntPtr.Zero;
96+
97+
CLRModule.Reset();
8198
}
8299

83100
/// <summary>

0 commit comments

Comments
 (0)
0