GitHub Viewer
using System.Reflection.Emit;
using System;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using Python.Runtime.Native;
using Python.Runtime.Platform;
using System.Linq;
namespace Python.Runtime
{
///
/// Encapsulates the low-level Python C API. Note that it is
/// the responsibility of the caller to have acquired the GIL
/// before calling any of these methods.
///
public class Runtime
{
public static int UCS => _UCS;
internal static readonly int _UCS = PyUnicode_GetMax() PyTuple_GetItem(pointer, new IntPtr(index));
internal static IntPtr PyTuple_GetItem(IntPtr pointer, long index)
{
return PyTuple_GetItem(pointer, new IntPtr(index));
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern BorrowedReference PyTuple_GetItem(BorrowedReference pointer, IntPtr index);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr PyTuple_GetItem(IntPtr pointer, IntPtr index);
internal static int PyTuple_SetItem(IntPtr pointer, long index, IntPtr value)
{
return PyTuple_SetItem(pointer, new IntPtr(index), value);
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern int PyTuple_SetItem(IntPtr pointer, IntPtr index, IntPtr value);
internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end)
{
return PyTuple_GetSlice(pointer, new IntPtr(start), new IntPtr(end));
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr PyTuple_GetSlice(IntPtr pointer, IntPtr start, IntPtr end);
internal static long PyTuple_Size(IntPtr pointer)
{
return (long)_PyTuple_Size(pointer);
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyTuple_Size")]
private static extern IntPtr _PyTuple_Size(IntPtr pointer);
//====================================================================
// Python iterator API
//====================================================================
internal static bool PyIter_Check(IntPtr pointer)
{
var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type);
IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext);
return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented;
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyIter_Next(IntPtr pointer);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern NewReference PyIter_Next(BorrowedReference pointer);
//====================================================================
// Python module API
//====================================================================
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyModule_New(string name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern string PyModule_GetName(IntPtr module);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyModule_GetDict(IntPtr module);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern string PyModule_GetFilename(IntPtr module);
#if PYTHON_WITH_PYDEBUG
[DllImport(_PythonDll, EntryPoint = "PyModule_Create2TraceRefs", CallingConvention = CallingConvention.Cdecl)]
#else
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
#endif
internal static extern IntPtr PyModule_Create2(IntPtr module, int apiver);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyImport_Import(IntPtr name);
///
/// Return value: New reference.
///
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyImport_ImportModule(string name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyImport_ReloadModule(IntPtr module);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyImport_AddModule(string name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyImport_GetModuleDict();
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PySys_SetArgvEx(
int argc,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv,
int updatepath
);
///
/// Return value: Borrowed reference.
/// Return the object name from the sys module or NULL if it does not exist, without setting an exception.
///
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern BorrowedReference PySys_GetObject(string name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PySys_SetObject(string name, IntPtr ob);
//====================================================================
// Python type object API
//====================================================================
internal static bool PyType_Check(IntPtr ob)
{
return PyObject_TypeCheck(ob, PyTypeType);
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyType_Modified(IntPtr type);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool PyType_IsSubtype(IntPtr t1, IntPtr t2);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern bool PyType_IsSubtype(BorrowedReference t1, BorrowedReference t2);
internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp)
=> PyObject_TypeCheck(new BorrowedReference(ob), new BorrowedReference(tp));
internal static bool PyObject_TypeCheck(BorrowedReference ob, BorrowedReference tp)
{
BorrowedReference t = PyObject_TYPE(ob);
return (t == tp) || PyType_IsSubtype(t, tp);
}
internal static bool PyType_IsSameAsOrSubtype(IntPtr type, IntPtr ofType)
{
return (type == ofType) || PyType_IsSubtype(type, ofType);
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw);
internal static IntPtr PyType_GenericAlloc(IntPtr type, long n)
{
return PyType_GenericAlloc(type, new IntPtr(n));
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr PyType_GenericAlloc(IntPtr type, IntPtr n);
///
/// Finalize a type object. This should be called on all type objects to finish their initialization. This function is responsible for adding inherited slots from a type’s base class. Return 0 on success, or return -1 and sets an exception on error.
///
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyType_Ready(IntPtr type);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr _PyType_Lookup(IntPtr type, IntPtr name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyObject_GenericGetAttr(IntPtr obj, IntPtr name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr _PyObject_GetDictPtr(IntPtr obj);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyObject_GC_Del(IntPtr tp);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyObject_GC_Track(IntPtr tp);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyObject_GC_UnTrack(IntPtr tp);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void _PyObject_Dump(IntPtr ob);
//====================================================================
// Python memory API
//====================================================================
internal static IntPtr PyMem_Malloc(long size)
{
return PyMem_Malloc(new IntPtr(size));
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr PyMem_Malloc(IntPtr size);
internal static IntPtr PyMem_Realloc(IntPtr ptr, long size)
{
return PyMem_Realloc(ptr, new IntPtr(size));
}
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr PyMem_Realloc(IntPtr ptr, IntPtr size);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyMem_Free(IntPtr ptr);
//====================================================================
// Python exception API
//====================================================================
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_SetString(IntPtr ob, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string message);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_SetObject(BorrowedReference type, BorrowedReference exceptionObject);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyErr_SetFromErrno(IntPtr ob);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_SetNone(IntPtr ob);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyErr_ExceptionMatches(IntPtr exception);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_NormalizeException(ref IntPtr ob, ref IntPtr val, ref IntPtr tb);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyErr_Occurred();
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_Fetch(out IntPtr ob, out IntPtr val, out IntPtr tb);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_Clear();
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern void PyErr_Print();
//====================================================================
// Cell API
//====================================================================
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern NewReference PyCell_Get(BorrowedReference cell);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyCell_Set(BorrowedReference cell, IntPtr value);
//====================================================================
// Python GC API
//====================================================================
internal const int _PyGC_REFS_SHIFT = 1;
internal const long _PyGC_REFS_UNTRACKED = -2;
internal const long _PyGC_REFS_REACHABLE = -3;
internal const long _PyGC_REFS_TENTATIVELY_UNREACHABLE = -4;
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyGC_Collect();
internal static IntPtr _Py_AS_GC(IntPtr ob)
{
// XXX: PyGC_Head has a force alignment depend on platform.
// See PyGC_Head in objimpl.h for more details.
return Is32Bit ? ob - 16 : ob - 24;
}
internal static IntPtr _Py_FROM_GC(IntPtr gc)
{
return Is32Bit ? gc + 16 : gc + 24;
}
internal static IntPtr _PyGCHead_REFS(IntPtr gc)
{
unsafe
{
var pGC = (PyGC_Head*)gc;
var refs = pGC->gc.gc_refs;
if (Is32Bit)
{
return new IntPtr(refs.ToInt32() >> _PyGC_REFS_SHIFT);
}
return new IntPtr(refs.ToInt64() >> _PyGC_REFS_SHIFT);
}
}
internal static IntPtr _PyGC_REFS(IntPtr ob)
{
return _PyGCHead_REFS(_Py_AS_GC(ob));
}
internal static bool _PyObject_GC_IS_TRACKED(IntPtr ob)
{
return (long)_PyGC_REFS(ob) != _PyGC_REFS_UNTRACKED;
}
internal static void Py_CLEAR(ref IntPtr ob)
{
XDecref(ob);
ob = IntPtr.Zero;
}
//====================================================================
// Python Capsules API
//====================================================================
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern NewReference PyCapsule_New(IntPtr pointer, string name, IntPtr destructor);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyCapsule_GetPointer(BorrowedReference capsule, string name);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int PyCapsule_SetPointer(BorrowedReference capsule, IntPtr pointer);
//====================================================================
// Miscellaneous
//====================================================================
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyMethod_Self(IntPtr ob);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr PyMethod_Function(IntPtr ob);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int Py_AddPendingCall(IntPtr func, IntPtr arg);
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
internal static extern int Py_MakePendingCalls();
internal static void SetNoSiteFlag()
{
var loader = LibraryLoader.Instance;
IntPtr dllLocal = IntPtr.Zero;
if (_PythonDll != "__Internal")
{
dllLocal = loader.Load(_PythonDll);
if (dllLocal == IntPtr.Zero)
{
throw new Exception($"Cannot load {_PythonDll}");
}
}
try
{
Py_NoSiteFlag = loader.GetFunction(dllLocal, "Py_NoSiteFlag");
Marshal.WriteInt32(Py_NoSiteFlag, 1);
}
finally
{
if (dllLocal != IntPtr.Zero)
{
loader.Free(dllLocal);
}
}
}
///
/// Return value: New reference.
///
internal static IntPtr GetBuiltins()
{
return PyImport_Import(PyIdentifier.builtins);
}
}
public enum ShutdownMode
{
Default,
Normal,
Soft,
Reload,
}
class PyReferenceCollection
{
private List _actions = new List();
///
/// Record obj's address to release the obj in the future,
/// obj must alive before calling Release.
///
public void Add(IntPtr ob, Action onRelease)
{
_actions.Add(new KeyValuePair(ob, onRelease));
}
public void Release()
{
foreach (var item in _actions)
{
Runtime.XDecref(item.Key);
item.Value?.Invoke();
}
_actions.Clear();
}
}
}