8000 Reset gchead and refchain after shutdown by amos402 · Pull Request #754 · pythonnet/pythonnet · GitHub
[go: up one dir, main page]

Skip to content

Reset gchead and refchain after shutdown #754

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Reset gchead and refchain after shutdown
  • Loading branch information
amos402 committed Oct 18, 2018
commit 1fae108ef67a88873d4a793abf849b212c126ab9
69 changes: 68 additions & 1 deletion src/runtime/pythonengine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
Expand All @@ -12,11 +13,16 @@ namespace Python.Runtime
/// </summary>
public class PythonEngine : IDisposable
{
private const int NUM_GENERATIONS = 3;

private static DelegateManager delegateManager;
private static bool initialized;
private static IntPtr _pythonHome = IntPtr.Zero;
private static IntPtr _programName = IntPtr.Zero;
private static IntPtr _pythonPath = IntPtr.Zero;
private static IntPtr _refChain = IntPtr.Zero;
private static IntPtr[] _generations;


public PythonEngine()
{
Expand Down Expand Up @@ -168,6 +174,10 @@ public static void Initialize(IEnumerable<string> args, bool setSysArgv = true)
initialized = true;
Exceptions.Clear();

_generations = GetGCGenerations();
#if PYTHON_WITH_PYDEBUG
_refChain = GetRefChainHead();
#endif
if (setSysArgv)
{
Py.SetArgv(args);
Expand Down Expand Up @@ -303,6 +313,7 @@ public static void Shutdown()
_pythonPath = IntPtr.Zero;

Runtime.Shutdown();
ResetGC();
initialized = false;
}
}
Expand Down Expand Up @@ -520,6 +531,62 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals,
}
}
}

internal static void ResetGC()
{
ClearGC();
#if PYTHON_WITH_PYDEBUG
ResetRefChain();
#endif
}

private static void ClearGC()
{
Debug.Assert(_generations != null);
foreach (IntPtr head in _generations)
{
// gc.gc_next
Marshal.WriteIntPtr(head, 0, head);
// gc.gc_prev
Marshal.WriteIntPtr(head, IntPtr.Size, head);
}
}

private static IntPtr[] GetGCGenerations()
{
int GCHeadOffset = IntPtr.Size == 4 ? 24 : 32;
IntPtr op = Runtime._PyObject_GC_New(Runtime.PyTypeType);
Runtime.PyObject_GC_Track(op);
IntPtr g = Runtime._Py_AS_GC(op);
// According to _PyObjct_GC_TRACK and PyGC_Head strcture, g is the g->gc.gc_next
// It also become the GEN_HEAD(0) now
IntPtr[] gens = new IntPtr[NUM_GENERATIONS];
for (int i = 0; i < NUM_GENERATIONS; i++)
{
gens[i] = g;
g += GCHeadOffset;
}
Runtime.PyObject_GC_UnTrack(op);
Runtime.PyObject_GC_Del(op);
return gens;
}

#if PYTHON_WITH_PYDEBUG
private static void ResetRefChain()
{
Debug.Assert(_refChain != IntPtr.Zero);
Marshal.WriteIntPtr(_refChain, ObjectOffset._ob_next, _refChain);
Marshal.WriteIntPtr(_refChain, ObjectOffset._ob_prev, _refChain);
}

private static IntPtr GetRefChainHead()
{
IntPtr op = Runtime._PyObject_GC_New(Runtime.PyBaseObjectType);
IntPtr refchain = Marshal.ReadIntPtr(op, ObjectOffset._ob_prev);
Runtime.PyObject_GC_Del(op);
return refchain;
}
#endif
}

public enum RunFlagType
Expand Down
6 changes: 5 additions & 1 deletion src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1575,7 +1575,7 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp)
internal static extern IntPtr _PyObject_GetDictPtr(IntPtr obj);

[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyObject_GC_New(IntPtr tp);
internal static extern IntPtr _PyObject_GC_New(IntPtr tp);

[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyObject_GC_Del(IntPtr tp);
Expand All @@ -1600,6 +1600,10 @@ internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp)
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyMem_Free(IntPtr ptr);

internal static IntPtr _Py_AS_GC(IntPtr op)
{
return op - IntPtr.Size;
}

//====================================================================
// Python exception API
Expand Down
0