Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Release method wrapper(split from #958) #1002

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

Merged
merged 5 commits into from
Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
44 changes: 37 additions & 7 deletions src/runtime/importhook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ internal static void InitializeModuleDef()
module_def = ModuleDefOffset.AllocModuleDef("clr");
}
}

internal static void ReleaseModuleDef()
{
if (module_def == IntPtr.Zero)
{
return;
}
ModuleDefOffset.FreeModuleDef(module_def);
module_def = IntPtr.Zero;
}
#endif

/// <summary>
Expand Down Expand Up @@ -56,9 +66,12 @@ static void InitImport()
// Python __import__.
IntPtr builtins = GetNewRefToBuiltins();
py_import = Runtime.PyObject_GetAttrString(builtins, "__import__");
PythonException.ThrowIfIsNull(py_import);

hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc");
Runtime.PyObject_SetAttrString(builtins, "__import__", hook.ptr);
Runtime.XDecref(hook.ptr);
int res = Runtime.PyObject_SetAttrString(builtins, "__import__", hook.ptr);
PythonException.ThrowIfIsNotZero(res);

Runtime.XDecref(builtins);
}

Expand All @@ -69,10 +82,14 @@ static void RestoreImport()
{
IntPtr builtins = GetNewRefToBuiltins();

Runtime.PyObject_SetAttrString(builtins, "__import__", py_import);
int res = Runtime.PyObject_SetAttrString(builtins, "__import__", py_import);
PythonException.ThrowIfIsNotZero(res);
Runtime.XDecref(py_import);
py_import = IntPtr.Zero;

hook.Release();
hook = null;

Runtime.XDecref(builtins);
}

Expand Down Expand Up @@ -112,13 +129,26 @@ internal static void Initialize()
/// </summary>
internal static void Shutdown()
{
if (Runtime.Py_IsInitialized() != 0)
if (Runtime.Py_IsInitialized() == 0)
{
RestoreImport();
return;
}

Runtime.XDecref(py_clr_module);
Runtime.XDecref(root.pyHandle);
RestoreImport();

bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1;
Runtime.XDecref(py_clr_module);
py_clr_module = IntPtr.Zero;
#if PYTHON3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid introducing another compile-time check, and use version info from Runtime class instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, in the modernisation branch I gave up on the idea of having Python 2 and 3 in the same codebase, especially considering the imminent EoL of Python 2. I do that by defaulting to Python 3 and letting the user supply PYTHON2 explicitly for the Py2 version. So here, to stay in line with that, it would be enough to change to #if !PYTHON2.

if (shouldFreeDef)
{
ReleaseModuleDef();
}
#endif

Runtime.XDecref(root.pyHandle);
root = null;
CLRModule.Reset();
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public static IntPtr AllocModuleDef(string modulename)
byte[] ascii = Encoding.ASCII.GetBytes(modulename);
int size = name + ascii.Length + 1;
IntPtr ptr = Marshal.AllocHGlobal(size);
for (int i = 0; i < m_free; i += IntPtr.Size)
for (int i = 0; i <= m_free; i += IntPtr.Size)
Marshal.WriteIntPtr(ptr, i, IntPtr.Zero);
Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length);
Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name));
Expand Down
17 changes: 17 additions & 0 deletions src/runtime/methodwrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ internal class MethodWrapper
{
public IntPtr mdef;
public IntPtr ptr;
private bool _disposed = false;

public MethodWrapper(Type type, string name, string funcType = null)
{
Expand All @@ -31,5 +32,21 @@ public IntPtr Call(IntPtr args, IntPtr kw)
{
return Runtime.PyCFunction_Call(ptr, args, kw);
}

public void Release()
{
if (_disposed)
{
return;
}
_disposed = true;
bool freeDef = Runtime.Refcount(ptr) == 1;
Runtime.XDecref(ptr);
if (freeDef && mdef != IntPtr.Zero)
{
Runtime.PyMem_Free(mdef);
mdef = IntPtr.Zero;
}
Comment on lines +43 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we call Release, and there are still references to the method, how is it going to be freed later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amos402 Could you comment on this question?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't release anymore, here's the only chance for now. Assume the ptr deallocating in another domain in the future, the cod in this domain had already been invalid, unless we use a C extension take place the ptr's tp_dealloc.

}
}
}
5 changes: 5 additions & 0 deletions src/runtime/moduleobject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ internal class CLRModule : ModuleObject
internal static bool _SuppressDocs = false;
internal static bool _SuppressOverloads = false;

static CLRModule()
{
Reset();
}

public CLRModule() : base("clr")
{
_namespace = string.Empty;
Expand Down
1 change: 0 additions & 1 deletion src/runtime/runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ internal static void Initialize(bool initSigs = false)

IsFinalizing = false;

CLRModule.Reset();
GenericUtil.Reset();
PyScopeManager.Reset();
ClassManager.Reset();
Expand Down