Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7caa7ed

Browse files
authored
Merge branch 'master' into fix_kwarg_func_resolution
2 parents1dd8725 +72fae73 commit7caa7ed

File tree

7 files changed

+75
-85
lines changed

7 files changed

+75
-85
lines changed

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
2727
- When calling C# from Python, enable passing argument of any type to a parameter of C# type`object` by wrapping it into`PyObject` instance. ([#881][i881])
2828
- Added support for kwarg parameters when calling .NET methods from Python
2929
- Changed method for finding MSBuild using vswhere
30+
- Reworked`Finalizer`. Now objects drop into its queue upon finalization, which is periodically drained when new objects are created.
3031

3132
###Fixed
3233

‎src/embed_tests/TestFinalizer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void CollectBasicObject()
7777
}
7878
try
7979
{
80-
Finalizer.Instance.Collect(forceDispose:false);
80+
Finalizer.Instance.Collect();
8181
}
8282
finally
8383
{

‎src/runtime/clrobject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ internal CLRObject(object ob, IntPtr tp)
3535
}
3636

3737

38-
internalstaticCLRObjectGetInstance(objectob,IntPtrpyType)
38+
staticCLRObjectGetInstance(objectob,IntPtrpyType)
3939
{
4040
returnnewCLRObject(ob,pyType);
4141
}
4242

4343

44-
internalstaticCLRObjectGetInstance(objectob)
44+
staticCLRObjectGetInstance(objectob)
4545
{
4646
ClassBasecc=ClassManager.GetClass(ob.GetType());
4747
returnGetInstance(ob,cc.tpHandle);

‎src/runtime/finalizer.cs

Lines changed: 33 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ public class ErrorArgs : EventArgs
2828
publicboolEnable{get;set;}
2929

3030
privateConcurrentQueue<IPyDisposable>_objQueue=newConcurrentQueue<IPyDisposable>();
31-
privatebool_pending=false;
32-
privatereadonlyobject_collectingLock=newobject();
33-
privateTask_finalizerTask;
31+
privateint_throttled;
3432

3533
#region FINALIZER_CHECK
3634

@@ -75,19 +73,16 @@ private Finalizer()
7573
Threshold=200;
7674
}
7775

78-
publicvoidCollect(boolforceDispose=true)
76+
[Obsolete("forceDispose parameter is unused. All objects are disposed regardless.")]
77+
publicvoidCollect(boolforceDispose)=>this.DisposeAll();
78+
publicvoidCollect()=>this.DisposeAll();
79+
80+
internalvoidThrottledCollect()
7981
{
80-
if(Instance._finalizerTask!=null
81-
&&!Instance._finalizerTask.IsCompleted)
82-
{
83-
varts=PythonEngine.BeginAllowThreads();
84-
Instance._finalizerTask.Wait();
85-
PythonEngine.EndAllowThreads(ts);
86-
}
87-
elseif(forceDispose)
88-
{
89-
Instance.DisposeAll();
90-
}
82+
_throttled=unchecked(this._throttled+1);
83+
if(!Enable||_throttled<Threshold)return;
84+
_throttled=0;
85+
this.Collect();
9186
}
9287

9388
publicList<WeakReference>GetCollectedObjects()
@@ -101,62 +96,18 @@ internal void AddFinalizedObject(IPyDisposable obj)
10196
{
10297
return;
10398
}
104-
if(Runtime.Py_IsInitialized()==0)
105-
{
106-
// XXX: Memory will leak if a PyObject finalized after Python shutdown,
107-
// for avoiding that case, user should call GC.Collect manual before shutdown.
108-
return;
109-
}
99+
110100
#ifFINALIZER_CHECK
111101
lock(_queueLock)
112102
#endif
113103
{
114-
_objQueue.Enqueue(obj);
115-
}
116-
GC.ReRegisterForFinalize(obj);
117-
if(!_pending&&_objQueue.Count>=Threshold)
118-
{
119-
AddPendingCollect();
104+
this._objQueue.Enqueue(obj);
120105
}
121106
}
122107

123108
internalstaticvoidShutdown()
124109
{
125-
if(Runtime.Py_IsInitialized()==0)
126-
{
127-
Instance._objQueue=newConcurrentQueue<IPyDisposable>();
128-
return;
129-
}
130-
Instance.Collect(forceDispose:true);
131-
}
132-
133-
privatevoidAddPendingCollect()
134-
{
135-
if(Monitor.TryEnter(_collectingLock))
136-
{
137-
try
138-
{
139-
if(!_pending)
140-
{
141-
_pending=true;
142-
// should already be complete but just in case
143-
_finalizerTask?.Wait();
144-
145-
_finalizerTask=Task.Factory.StartNew(()=>
146-
{
147-
using(Py.GIL())
148-
{
149-
Instance.DisposeAll();
150-
_pending=false;
151-
}
152-
});
153-
}
154-
}
155-
finally
156-
{
157-
Monitor.Exit(_collectingLock);
158-
}
159-
}
110+
Instance.DisposeAll();
160111
}
161112

162113
privatevoidDisposeAll()
@@ -178,12 +129,18 @@ private void DisposeAll()
178129
try
179130
{
180131
obj.Dispose();
181-
Runtime.CheckExceptionOccurred();
182132
}
183133
catch(Exceptione)
184134
{
185-
// We should not bother the main thread
186-
ErrorHandler?.Invoke(this,newErrorArgs()
135+
varhandler=ErrorHandler;
136+
if(handlerisnull)
137+
{
138+
thrownewFinalizationException(
139+
"Python object finalization failed",
140+
disposable:obj,innerException:e);
141+
}
142+
143+
handler.Invoke(this,newErrorArgs()
187144
{
188145
Error=e
189146
});
@@ -267,4 +224,15 @@ private void ValidateRefCount()
267224
}
268225
#endif
269226
}
227+
228+
publicclassFinalizationException:Exception
229+
{
230+
publicIPyDisposableDisposable{get;}
231+
232+
publicFinalizationException(stringmessage,IPyDisposabledisposable,ExceptioninnerException)
233+
:base(message,innerException)
234+
{
235+
this.Disposable=disposable??thrownewArgumentNullException(nameof(disposable));
236+
}
237+
}
270238
}

‎src/runtime/pyobject.cs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ public class PyObject : DynamicObject, IEnumerable, IPyDisposable
3030
#endif
3131

3232
protectedinternalIntPtrobj=IntPtr.Zero;
33-
privatebooldisposed=false;
34-
privatebool_finalized=false;
3533

3634
internalBorrowedReferenceReference=>newBorrowedReference(obj);
3735

@@ -49,6 +47,7 @@ public PyObject(IntPtr ptr)
4947
if(ptr==IntPtr.Zero)thrownewArgumentNullException(nameof(ptr));
5048

5149
obj=ptr;
50+
Finalizer.Instance.ThrottledCollect();
5251
#ifTRACE_ALLOC
5352
Traceback=newStackTrace(1);
5453
#endif
@@ -64,6 +63,7 @@ internal PyObject(BorrowedReference reference)
6463
if(reference.IsNull)thrownewArgumentNullException(nameof(reference));
6564

6665
obj=Runtime.SelfIncRef(reference.DangerousGetAddress());
66+
Finalizer.Instance.ThrottledCollect();
6767
#ifTRACE_ALLOC
6868
Traceback=newStackTrace(1);
6969
#endif
@@ -74,6 +74,7 @@ internal PyObject(BorrowedReference reference)
7474
[Obsolete("Please, always use PyObject(*Reference)")]
7575
protectedPyObject()
7676
{
77+
Finalizer.Instance.ThrottledCollect();
7778
#ifTRACE_ALLOC
7879
Traceback=newStackTrace(1);
7980
#endif
@@ -87,12 +88,6 @@ protected PyObject()
8788
{
8889
return;
8990
}
90-
if(_finalized||disposed)
91-
{
92-
return;
93-
}
94-
// Prevent a infinity loop by calling GC.WaitForPendingFinalizers
95-
_finalized=true;
9691
Finalizer.Instance.AddFinalizedObject(this);
9792
}
9893

@@ -183,17 +178,41 @@ public T As<T>()
183178
/// </remarks>
184179
protectedvirtualvoidDispose(booldisposing)
185180
{
186-
if(!disposed)
181+
if(this.obj==IntPtr.Zero)
187182
{
188-
if(Runtime.Py_IsInitialized()>0&&!Runtime.IsFinalizing)
183+
return;
184+
}
185+
186+
if(Runtime.Py_IsInitialized()==0)
187+
thrownewInvalidOperationException("Python runtime must be initialized");
188+
189+
if(!Runtime.IsFinalizing)
190+
{
191+
longrefcount=Runtime.Refcount(this.obj);
192+
Debug.Assert(refcount>0,"Object refcount is 0 or less");
193+
194+
if(refcount==1)
195+
{
196+
Runtime.PyErr_Fetch(outvarerrType,outvarerrVal,outvartraceback);
197+
198+
try
199+
{
200+
Runtime.XDecref(this.obj);
201+
Runtime.CheckExceptionOccurred();
202+
}
203+
finally
204+
{
205+
// Python requires finalizers to preserve exception:
206+
// https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation
207+
Runtime.PyErr_Restore(errType,errVal,traceback);
208+
}
209+
}
210+
else
189211
{
190-
IntPtrgs=PythonEngine.AcquireLock();
191-
Runtime.XDecref(obj);
192-
obj=IntPtr.Zero;
193-
PythonEngine.ReleaseLock(gs);
212+
Runtime.XDecref(this.obj);
194213
}
195-
disposed=true;
196214
}
215+
this.obj=IntPtr.Zero;
197216
}
198217

199218
publicvoidDispose()

‎src/runtime/pythonengine.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public static string PythonHome
8080
}
8181
set
8282
{
83+
// this value is null in the beginning
8384
Marshal.FreeHGlobal(_pythonHome);
8485
_pythonHome=UcsMarshaler.Py3UnicodePy2StringtoPtr(value);
8586
Runtime.Py_SetPythonHome(_pythonHome);

‎src/runtime/runtime.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
usingSystem;
2+
usingSystem.Diagnostics.Contracts;
23
usingSystem.Runtime.InteropServices;
34
usingSystem.Security;
45
usingSystem.Text;
@@ -8,7 +9,6 @@
89

910
namespacePython.Runtime
1011
{
11-
1212
/// <summary>
1313
/// Encapsulates the low-level Python C API. Note that it is
1414
/// the responsibility of the caller to have acquired the GIL
@@ -106,7 +106,7 @@ public class Runtime
106106
internalstaticobjectIsFinalizingLock=newobject();
107107
internalstaticboolIsFinalizing;
108108

109-
internalstaticboolIs32Bit=IntPtr.Size==4;
109+
internalstaticboolIs32Bit=>IntPtr.Size==4;
110110

111111
// .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
112112
internalstaticboolIsWindows=Environment.OSVersion.Platform==PlatformID.Win32NT;
@@ -659,6 +659,7 @@ internal static unsafe void XDecref(IntPtr op)
659659
#endif
660660
}
661661

662+
[Pure]
662663
internalstatic unsafelong Refcount(IntPtrop)
663664
{
664665
var p=(void*)op;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp