8000 fixed sending PyObject across domain boundary · quantfns/pythonnet@a8ef06c · GitHub
[go: up one dir, main page]

Skip to content

Commit a8ef06c

Browse files
committed
fixed sending PyObject across domain boundary
removed debug code, that ensured Python GC list integrity
1 parent 2fdbf0e commit a8ef06c

26 files changed

+107
-90
lines changed

src/embed_tests/TestRuntime.cs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,6 @@ public static void Py_IsInitializedValue()
3232
Assert.AreEqual(0, Runtime.Runtime.Py_IsInitialized());
3333
}
3434

35-
[Test]
36-
public static void IterAcrossRuns< B421 span class=pl-kos>()
37-
{
38-
Runtime.Runtime.Py_Initialize();
39-
BorrowedReference builtins = Runtime.Runtime.PyEval_GetBuiltins();
40-
BorrowedReference iter = Runtime.Runtime.PyDict_GetItemString(builtins, "iter");
41-
42-
using var ownedIter = new NewReference(iter);
43-
Runtime.Runtime.Py_Finalize();
44-
45-
Runtime.Runtime.Py_Initialize();
46-
ownedIter.Dispose();
47-
Runtime.Runtime.Py_Finalize();
48-
}
49-
5035
[Test]
5136
public static void RefCountTest()
5237
{

src/runtime/ReflectedClrType.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Runtime.Serialization;
34

45
using static Python.Runtime.PythonException;
56

@@ -10,6 +11,7 @@ internal sealed class ReflectedClrType : PyType
1011
{
1112
private ReflectedClrType(StolenReference reference) : base(reference, prevalidated: true) { }
1 F438 213
internal ReflectedClrType(ReflectedClrType original) : base(original, prevalidated: true) { }
14+
ReflectedClrType(SerializationInfo info, StreamingContext context) : base(info, context) { }
1315

1416
internal ClassBase Impl => (ClassBase)ManagedType.GetManagedObject(this)!;
1517

src/runtime/classbase.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ public static NewReference tp_repr(BorrowedReference ob)
337337
/// </summary>
338338
public static void tp_dealloc(NewReference lastRef)
339339
{
340-
Runtime.PyGC_ValidateLists();
341340
Runtime.PyObject_GC_UnTrack(lastRef.Borrow());
342341

343342
CallClear(lastRef.Borrow());
@@ -347,12 +346,10 @@ public static void tp_dealloc(NewReference lastRef)
347346
Debug.Assert(deleted);
348347

349348
DecrefTypeAndFree(lastRef.Steal());
350-
Runtime.PyGC_ValidateLists();
351349
}
352350

353351
public static int tp_clear(BorrowedReference ob)
354352
{
355-
Runtime.PyGC_ValidateLists();
356353
GCHandle? gcHandle = TryGetGCHandle(ob);
357354
gcHandle?.Free();
358355

@@ -363,7 +360,6 @@ public static int tp_clear(BorrowedReference ob)
363360
}
364361

365362
ClearObjectDict(ob);
366-
Runtime.PyGC_ValidateLists();
367363
return 0;
368364
}
369365

src/runtime/classderived.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ internal ClassDerivedObject(Type tp) : base(tp)
6969

7070
public new static void tp_dealloc(NewReference ob)
7171
{
72-
Runtime.PyGC_ValidateLists();
7372
var self = (CLRObject)GetManagedObject(ob.Borrow())!;
7473

7574
// don't let the python GC destroy this object
@@ -83,7 +82,6 @@ internal ClassDerivedObject(Type tp) : base(tp)
8382
GCHandle gc = GCHandle.Alloc(self, GCHandleType.Weak);
8483
SetGCHandle(ob.Borrow(), gc);
8584
oldHandle.Free();
86-
Runtime.PyGC_ValidateLists();
8785
}
8886

8987
/// <summary>

src/runtime/constructorbinding.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,7 @@ public static int tp_traverse(BorrowedReference ob, IntPtr visit, IntPtr arg)
152152
var self = (ConstructorBinding?)GetManagedObject(ob);
153153
if (self is null) return 0;
154154

155-
Runtime.PyGC_ValidateLists();
156155
int res = PyVisit(self.typeToCreate, visit, arg);
157-
Runtime.PyGC_ValidateLists();
158156
return res;
159157
}
160158
}
@@ -237,9 +235,7 @@ public static int tp_traverse(BorrowedReference ob, IntPtr visit, IntPtr arg)
237235
var self = (BoundContructor?)GetManagedObject(ob);
238236
if (self is null) return 0;
239237

240-
Runtime.PyGC_ValidateLists();
241238
int res = PyVisit(self.typeToCreate, visit, arg);
242-
Runtime.PyGC_ValidateLists();
243239
return res;
244240
}
245241
}

src/runtime/extensiontype.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ public static int tp_setattro(BorrowedReference ob, BorrowedReference key, Borro
7676

7777
public unsafe static void tp_dealloc(NewReference lastRef)
7878
{
79-
Runtime.PyGC_ValidateLists();
8079
Runtime.PyObject_GC_UnTrack(lastRef.Borrow());
8180

8281
tp_clear(lastRef.Borrow());
@@ -86,18 +85,15 @@ public unsafe static void tp_dealloc(NewReference lastRef)
8685

8786
// we must decref our type: https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_dealloc
8887
DecrefTypeAndFree(lastRef.Steal());
89-
Runtime.PyGC_ValidateLists();
9088
}
9189

9290
public static int tp_clear(BorrowedReference ob)
9391
{
94-
Runtime.PyGC_ValidateLists();
9592
GCHandle? gcHandle = TryGetGCHandle(ob);
9693
gcHandle?.Free();
9794
if (gcHandle is not null) SetGCHandle(ob, default);
9895

9996
int res = ClassBase.BaseUnmanagedClear(ob);
100-
Runtime.PyGC_ValidateLists();
10197
return res;
10298
}
10399

src/runtime/finalizer.cs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,30 @@ internal List<IntPtr> GetCollectedObjects()
122122
return _objQueue.Select(o => o.PyObj).ToList();
123123
}
124124

125-
internal void AddFinalizedObject(ref IntPtr obj, int run)
125+
internal void AddFinalizedObject(ref IntPtr obj, int run
126+
#if TRACE_ALLOC
127+
, StackTrace stackTrace
128+
#endif
129+
)
126130
{
127131
Debug.Assert(obj != IntPtr.Zero);
128132
if (!Enable)
129133
{
130134
return;
131135
}
132136

137+
Debug.Assert(Runtime.Refcount(new BorrowedReference(obj)) > 0);
138+
133139
#if FINALIZER_CHECK
134140
lock (_queueLock)
135141
#endif
136142
{
137-
this._objQueue.Enqueue(new PendingFinalization { PyObj = obj, RuntimeRun = run });
143+
this._objQueue.Enqueue(new PendingFinalization {
144+
PyObj = obj, RuntimeRun = run,
145+
#if TRACE_ALLOC
146+
StackTrace = stackTrace.ToString(),
147+
#endif
148+
});
138149
}
139150
obj = IntPtr.Zero;
140151
}
@@ -165,10 +176,12 @@ internal static void Shutdown()
165176
Instance.started = false;
166177
}
167178

168-
private void DisposeAll()
179+
internal nint DisposeAll()
169180
{
170181
if (_objQueue.IsEmpty && _derivedQueue.IsEmpty)
171-
return;
182+
return 0;
183+
184+
nint collected = 0;
172185

173186
BeforeCollect?.Invoke(this, new CollectArgs()
174187
{
@@ -200,16 +213,8 @@ private void DisposeAll()
200213
}
201214

202215
IntPtr copyForException = obj.PyObj;
203-
Runtime.PyGC_ValidateLists();
204-
var @ref = new BorrowedReference(obj.PyObj);
205-
nint refs = Runtime.Refcount(@ref);
206-
var type = Runtime.PyObject_TYPE(@ref);
207-
string typeName = Runtime.ToString(type);
208-
if (typeName == "<class 'clr.interop.PyErr'>")
209-
{
210-
211-
}
212216
Runtime.XDecref(StolenReference.Take(ref obj.PyObj));
217+
collected++;
213218
try
214219
{
215220
Runtime.CheckExceptionOccurred();
@@ -218,7 +223,6 @@ private void DisposeAll()
218223
{
219224
HandleFinalizationException(obj.PyObj, e);
220225
}
221-
Runtime.PyGC_ValidateLists();
222226
}
223227

224228
while (!_derivedQueue.IsEmpty)
@@ -241,6 +245,7 @@ private void DisposeAll()
241245
// matches correspdonging PyObject_GC_UnTrack
242246
// in ClassDerivedObject.tp_dealloc
243247
Runtime.PyObject_GC_Del(@ref.Steal());
248+
collected++;
244249

245250
gcHandle.Free();
246251
}
@@ -252,6 +257,7 @@ private void DisposeAll()
252257
Runtime.PyErr_Restore(errType.StealNullable(), errVal.StealNullable(), traceback.StealNullable());
253258
}
254259
}
260+
return collected;
255261
}
256262

257263
void HandleFinalizationException(IntPtr obj, Exception cause)
@@ -341,6 +347,9 @@ struct PendingFinalization
341347
{
342348
public IntPtr PyObj;
343349
public int RuntimeRun;
350+
#if TRACE_ALLOC
351+
public string StackTrace;
352+
#endif
344353
}
345354

346355
public class FinalizationException : Exception

src/runtime/metatype.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,6 @@ public static NewReference mp_subscript(BorrowedReference tp, BorrowedReference
290290
/// </summary>
291291
public static void tp_dealloc(NewReference lastRef)
292292
{
293-
Runtime.PyGC_ValidateLists();
294293
// Fix this when we dont cheat on the handle for subclasses!
295294

296295
var flags = PyType.GetFlags(lastRef.Borrow());
@@ -318,7 +317,6 @@ public static void tp_dealloc(NewReference lastRef)
318317
// We must decref our type.
319318
// type_dealloc from PyType will use it to get tp_free so we must keep the value
320319
Runtime.XDecref(StolenReference.DangerousFromPointer(op.DangerousGetAddress()));
321-
Runtime.PyGC_ValidateLists();
322320
}
323321

324322
private static NewReference DoInstanceCheck(BorrowedReference tp, BorrowedReference args, bool checkType)

src/runtime/module.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using System.Collections.Generic;
44
using System.Dynamic;
5+
using System.Runtime.Serialization;
56

67
namespace Python.Runtime
78
{
@@ -42,6 +43,9 @@ internal PyModule(in StolenReference reference) : base(reference)
4243
}
4344
}
4445

46+
protected PyModule(SerializationInfo info, StreamingContext context)
47+
: base(info, context) { }
48+
4549
private void InitializeBuiltins()
4650
{
4751
int res = Runtime.PyDict_SetItem(

src/runtime/moduleobject.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,16 +323,12 @@ public static int tp_traverse(BorrowedReference ob, IntPtr visit, IntPtr arg)
323323
var self = (ModuleObject?)GetManagedObject(ob);
324324
if (self is null) return 0;
325325

326-
Runtime.PyGC_ValidateLists();
327326
Debug.Assert(self.dict == GetObjectDict(ob));
328327
int res = PyVisit(self.dict, visit, arg);
329-
Runtime.PyGC_ValidateLists();
330328
if (res != 0) return res;
331329
foreach (var attr in self.cache.Values)
332330
{
333-
Runtime.PyGC_ValidateLists();
334331
res = PyVisit(attr, visit, arg);
335-
Runtime.PyGC_ValidateLists();
336332
if (res != 0) return res;
337333
}
338334
return 0;

src/runtime/pybuffer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,11 @@ private void Dispose(bool disposing)
240240

241241
if (_view.obj != IntPtr.Zero)
242242
{
243-
Finalizer.Instance.AddFinalizedObject(ref _view.obj, _exporter.run);
243+
Finalizer.Instance.AddFinalizedObject(ref _view.obj, _exporter.run
244+
#if TRACE_ALLOC
245+
, _exporter.Traceback
246+
#endif
247+
);
244248
}
245249

246250
Dispose(false);

src/runtime/pydict.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.Serialization;
23

34
namespace Python.Runtime
45
{
@@ -33,6 +34,9 @@ public PyDict() : base(Runtime.PyDict_New().StealOrThrow()) { }
3334
}
3435
}
3536

37+
protected PyDict(SerializationInfo info, StreamingContext context)
38+
: base(info, context) { }
39+
3640

3741
/// <summary>
3842
/// IsDictType Method

src/runtime/pyfloat.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.Serialization;
23

34
namespace Python.Runtime
45
{
@@ -70,6 +71,9 @@ public PyFloat(string value) : base(FromString(value))
7071
{
7172
}
7273

74+
protected PyFloat(SerializationInfo info, StreamingContext context)
75+
: base(info, context) { }
76+
7377

7478
/// <summary>
7579
/// IsFloatType Method

src/runtime/pyint.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.Serialization;
23

34
namespace Python.Runtime
45
{
@@ -134,6 +135,9 @@ public PyInt(string value) : base(Runtime.PyLong_FromString(value, 0).StealOrThr
134135
{
135136
}
136137

138+
protected PyInt(SerializationInfo info, StreamingContext context)
139+
: base(info, context) { }
140+
137141

138142
/// <summary>
139143
/// IsIntType Method

src/runtime/pyiter.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.Serialization;
34

45
namespace Python.Runtime
56
{
@@ -89,5 +90,17 @@ public void Reset()
8990

9091
public PyObject Current => _current ?? throw new InvalidOperationException();
9192
object System.Collections.IEnumerator.Current => Current;
93+
94+
protected PyIter(SerializationInfo info, StreamingContext context)
95+
: base(info, context)
96+
{
97+
_current = (PyObject?)info.GetValue("c", typeof(PyObject));
98+
}
99+
100+
protected override void GetObjectData(SerializationInfo info, StreamingContext context)
101+
{
102+
base.GetObjectData(info, context);
103+
info.AddValue("c", _current);
104+
}
92105
}
93106
}

src/runtime/pyiterable.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4+
using System.Runtime.Serialization;
45

56
namespace Python.Runtime
67
{
@@ -9,6 +10,8 @@ public class PyIterable : PyObject, IEnumerable<PyObject>
910
{
1011
internal PyIterable(BorrowedReference reference) : base(reference) { }
1112
internal PyIterable(in StolenReference reference) : base(reference) { }
13+
protected PyIterable(SerializationInfo info, StreamingContext context)
14+
: base(info, context) { }
1215

1316
/// <summary>
1417
/// Creates new instance from an existing object.

0 commit comments

Comments
 (0)
0