diff --git a/src/runtime/Native/PyConfig.cs b/src/runtime/Native/PyConfig.cs new file mode 100644 index 000000000..7d5021d65 --- /dev/null +++ b/src/runtime/Native/PyConfig.cs @@ -0,0 +1,36 @@ +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime.Native; + +#pragma warning disable CS0169 + +[StructLayout(LayoutKind.Sequential)] +struct PyConfig +{ + int _config_init; + public int isolated; + int use_environment; + int dev_mode; + public int install_signal_handlers; + + // Create an int array of size 256 as padding + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] + int[] padding; +} + +public enum PyStatusType : int +{ + PyStatus_Ok, + PyStatus_Error, + PyStatus_Exception, + PyStatus_Exit +} + +struct PyStatus +{ + public PyStatusType type; + IntPtr func; + IntPtr err_msg; + int exitcode; +} diff --git a/src/runtime/Runtime.Delegates.cs b/src/runtime/Runtime.Delegates.cs index 6490c3fe5..b649d6b20 100644 --- a/src/runtime/Runtime.Delegates.cs +++ b/src/runtime/Runtime.Delegates.cs @@ -281,6 +281,10 @@ static Delegates() PyType_Type = GetFunctionByName(nameof(PyType_Type), GetUnmanagedDll(_PythonDll)); Py_NoSiteFlag = (int*)GetFunctionByName(nameof(Py_NoSiteFlag), GetUnmanagedDll(_PythonDll)); + + PyConfig_InitPythonConfig = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyConfig_InitPythonConfig), GetUnmanagedDll(_PythonDll)); + Py_InitializeFromConfig = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(Py_InitializeFromConfig), GetUnmanagedDll(_PythonDll)); + PyConfig_Clear = (delegate* unmanaged[Cdecl])GetFunctionByName(nameof(PyConfig_Clear), GetUnmanagedDll(_PythonDll)); } static global::System.IntPtr GetUnmanagedDll(string? libraryName) @@ -540,5 +544,9 @@ static Delegates() internal static delegate* unmanaged[Cdecl] _Py_IsFinalizing { get; } internal static IntPtr PyType_Type { get; } internal static int* Py_NoSiteFlag { get; } + + internal static delegate* unmanaged[Cdecl] PyConfig_InitPythonConfig { get; } + internal static delegate* unmanaged[Cdecl] Py_InitializeFromConfig { get; } + internal static delegate* unmanaged[Cdecl] PyConfig_Clear { get; } } } diff --git a/src/runtime/Runtime.cs b/src/runtime/Runtime.cs index 2bd2aad3b..9888033f8 100644 --- a/src/runtime/Runtime.cs +++ b/src/runtime/Runtime.cs @@ -53,6 +53,8 @@ private static string GetDefaultDllName(Version version) return prefix + "python" + suffix + ext; } + private static PyConfig _configs = new PyConfig(); + private static bool _isInitialized = false; internal static bool IsInitialized => _isInitialized; private static bool _typesInitialized = false; @@ -117,7 +119,7 @@ internal static void Initialize(bool initSigs = false) ); if (!interpreterAlreadyInitialized) { - Py_InitializeEx(initSigs ? 1 : 0); + Py_InitializeFromConfig(initSigs ? 1 : 0); NewRun(); @@ -144,6 +146,7 @@ internal static void Initialize(bool initSigs = false) NewRun(); } } + MainManagedThreadId = Thread.CurrentThread.ManagedThreadId; Finalizer.Initialize(); @@ -190,6 +193,21 @@ internal static void Initialize(bool initSigs = false) hexCallable = new(() => new PyString("%x").GetAttr("__mod__")); } + static void Py_InitializeFromConfig(int install_signal_handlers) + { + // Initialize PyConfig + Delegates.PyConfig_InitPythonConfig(out _configs); + _configs.isolated = 1; + _configs.install_signal_handlers = install_signal_handlers; + + PyStatus status = Delegates.Py_InitializeFromConfig(ref _configs); + if (status.type != PyStatusType.PyStatus_Ok) + { + Delegates.PyConfig_Clear(ref _configs); + // Handle initialization error + } + } + static void NewRun() { run++; @@ -329,6 +347,8 @@ internal static void Shutdown() { PyGILState_Release(state); } + + Delegates.PyConfig_Clear(ref _configs); } const int MaxCollectRetriesOnShutdown = 20;