Skip to content
This repository was archived by the owner on Jul 22, 2023. It is now read-only.

Commit 799d37e

Browse files
committed
Clean up the test and interface
1 parent f66697d commit 799d37e

2 files changed

Lines changed: 49 additions & 35 deletions

File tree

src/embed_tests/TestFinalizer.cs

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
using NUnit.Framework;
22
using Python.Runtime;
33
using System;
4+
using System.Linq;
45
using System.Threading;
56

67
namespace Python.EmbeddingTest
78
{
89
public class TestFinalizer
910
{
1011
private string _PYTHONMALLOC = string.Empty;
12+
private int _oldThreshold;
1113

1214
[SetUp]
1315
public void SetUp()
@@ -21,13 +23,15 @@ public void SetUp()
2123
_PYTHONMALLOC = string.Empty;
2224
}
2325
Environment.SetEnvironmentVariable("PYTHONMALLOC", "malloc");
26+
_oldThreshold = Finalizer.Instance.Threshold;
2427
PythonEngine.Initialize();
2528
Exceptions.Clear();
2629
}
2730

2831
[TearDown]
2932
public void TearDown()
3033
{
34+
Finalizer.Instance.Threshold = _oldThreshold;
3135
PythonEngine.Shutdown();
3236
if (string.IsNullOrEmpty(_PYTHONMALLOC))
3337
{
@@ -56,41 +60,42 @@ public void CollectBasicObject()
5660
Assert.GreaterOrEqual(e.ObjectCount, 1);
5761
called = true;
5862
};
59-
Finalizer.Instance.CollectOnce += handler;
60-
try
61-
{
62-
FullGCCollect();
63-
PyLong obj = new PyLong(1024);
6463

65-
WeakReference shortWeak = new WeakReference(obj);
66-
WeakReference longWeak = new WeakReference(obj, true);
67-
obj = null;
68-
FullGCCollect();
69-
// The object has been resurrected
70-
// FIXME: Sometimes the shortWeak would get alive
71-
//Assert.IsFalse(shortWeak.IsAlive);
72-
Assert.IsTrue(longWeak.IsAlive);
64+
WeakReference shortWeak;
65+
WeakReference longWeak;
66+
{
67+
MakeAGarbage(out shortWeak, out longWeak);
68+
}
69+
FullGCCollect();
70+
// The object has been resurrected
71+
Assert.IsFalse(shortWeak.IsAlive);
72+
Assert.IsTrue(longWeak.IsAlive);
7373

74-
Assert.IsFalse(called);
74+
{
7575
var garbage = Finalizer.Instance.GetCollectedObjects();
7676
Assert.NotZero(garbage.Count);
77-
// FIXME: If make some query for garbage,
78-
// the above case will failed Assert.IsFalse(shortWeak.IsAlive)
79-
//Assert.IsTrue(garbage.All(T => T.IsAlive));
77+
Assert.IsTrue(garbage.Any(T => ReferenceEquals(T.Target, longWeak.Target)));
78+
}
8079

80+
Assert.IsFalse(called);
81+
Finalizer.Instance.CollectOnce += handler;
82+
try
83+
{
8184
Finalizer.Instance.CallPendingFinalizers();
82-
Assert.IsTrue(called);
83-
84-
FullGCCollect();
85-
//Assert.IsFalse(garbage.All(T => T.IsAlive));
86-
87-
Assert.IsNull(longWeak.Target);
8885
}
8986
finally
9087
{
9188
Finalizer.Instance.CollectOnce -= handler;
9289
}
90+
Assert.IsTrue(called);
91+
}
9392

93+
private static void MakeAGarbage(out WeakReference shortWeak, out WeakReference longWeak)
94+
{
95+
PyLong obj = new PyLong(1024);
96+
shortWeak = new WeakReference(obj);
97+
longWeak = new WeakReference(obj, true);
98+
obj = null;
9499
}
95100

96101
private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale)
@@ -101,7 +106,7 @@ private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale)
101106
FullGCCollect();
102107
FullGCCollect();
103108
pyCollect.Invoke();
104-
Finalizer.Instance.CallPendingFinalizers();
109+
Finalizer.Instance.Collect();
105110
Finalizer.Instance.Enable = enbale;
106111

107112
// Estimate unmanaged memory size
@@ -116,7 +121,7 @@ private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale)
116121
pyCollect.Invoke();
117122
if (enbale)
118123
{
119-
Finalizer.Instance.CallPendingFinalizers();
124+
Finalizer.Instance.Collect();
120125
}
121126

122127
FullGCCollect();

src/runtime/finalizer.cs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ public class CollectArgs : EventArgs
2222

2323
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
2424
private delegate int PedingCall(IntPtr arg);
25-
private PedingCall _collectAction;
25+
private readonly PedingCall _collectAction;
26+
2627
private bool _pending = false;
2728
private readonly object _collectingLock = new object();
2829
public int Threshold { get; set; }
@@ -32,7 +33,7 @@ private Finalizer()
3233
{
3334
Enable = true;
3435
Threshold = 200;
35-
_collectAction = OnCollect;
36+
_collectAction = OnPendingCollect;
3637
}
3738

3839
public void CallPendingFinalizers()
@@ -44,6 +45,14 @@ public void CallPendingFinalizers()
4445
Runtime.Py_MakePendingCalls();
4546
}
4647

48+
public void Collect()
49+
{
50+
using (var gilState = new Py.GILState())
51+
{
52+
DisposeAll();
53+
}
54+
}
55+
4756
public List<WeakReference> GetCollectedObjects()
4857
{
4958
return _objQueue.Select(T => new WeakReference(T)).ToList();
@@ -65,7 +74,7 @@ internal void AddFinalizedObject(IDisposable obj)
6574
GC.ReRegisterForFinalize(obj);
6675
if (_objQueue.Count >= Threshold)
6776
{
68-
Collect();
77+
AddPendingCollect();
6978
}
7079
}
7180

@@ -76,7 +85,7 @@ internal static void Shutdown()
7685
Runtime.PyErr_Clear();
7786
}
7887

79-
private void Collect()
88+
private void AddPendingCollect()
8089
{
8190
lock (_collectingLock)
8291
{
@@ -94,19 +103,19 @@ private void Collect()
94103
}
95104
}
96105

97-
private int OnCollect(IntPtr arg)
106+
private int OnPendingCollect(IntPtr arg)
98107
{
99-
CollectOnce?.Invoke(this, new CollectArgs()
100-
{
101-
ObjectCount = _objQueue.Count
102-
});
103-
DisposeAll();
108+
Collect();
104109
_pending = false;
105110
return 0;
106111
}
107112

108113
private void DisposeAll()
109114
{
115+
CollectOnce?.Invoke(this, new CollectArgs()
116+
{
117+
ObjectCount = _objQueue.Count
118+
});
110119
IDisposable obj;
111120
while (_objQueue.TryDequeue(out obj))
112121
{

0 commit comments

Comments
 (0)