| /* |
| pybind11/subinterpreter.h: Support for creating and using subinterpreters |
| |
| Copyright (c) 2025 The Pybind Development Team. |
| |
| All rights reserved. Use of this source code is governed by a |
| BSD-style license that can be found in the LICENSE file. |
| */ |
| |
| #pragma once |
| |
| #include "detail/common.h" |
| #include "detail/internals.h" |
| #include "gil.h" |
| |
| #include <stdexcept> |
| |
| #ifndef PYBIND11_HAS_SUBINTERPRETER_SUPPORT |
| # error "This platform does not support subinterpreters, do not include this file." |
| #endif |
| |
| PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
| PYBIND11_NAMESPACE_BEGIN(detail) |
| inline PyInterpreterState *get_interpreter_state_unchecked() { |
| auto cur_tstate = get_thread_state_unchecked(); |
| if (cur_tstate) |
| return cur_tstate->interp; |
| else |
| return nullptr; |
| } |
| PYBIND11_NAMESPACE_END(detail) |
| |
| class subinterpreter; |
| |
| /// Activate the subinterpreter and acquire its GIL, while also releasing any GIL and interpreter |
| /// currently held. Upon exiting the scope, the previous subinterpreter (if any) and its |
| /// associated GIL are restored to their state as they were before the scope was entered. |
| class subinterpreter_scoped_activate { |
| public: |
| explicit subinterpreter_scoped_activate(subinterpreter const &si); |
| ~subinterpreter_scoped_activate(); |
| |
| subinterpreter_scoped_activate(subinterpreter_scoped_activate &&) = delete; |
| subinterpreter_scoped_activate(subinterpreter_scoped_activate const &) = delete; |
| subinterpreter_scoped_activate &operator=(subinterpreter_scoped_activate &) = delete; |
| subinterpreter_scoped_activate &operator=(subinterpreter_scoped_activate const &) = delete; |
| |
| private: |
| PyThreadState *old_tstate_ = nullptr; |
| PyThreadState *tstate_ = nullptr; |
| PyGILState_STATE gil_state_; |
| bool simple_gil_ = false; |
| }; |
| |
| /// Holds a Python subinterpreter instance |
| class subinterpreter { |
| public: |
| /// empty/unusable, but move-assignable. use create() to create a subinterpreter. |
| subinterpreter() = default; |
| |
| subinterpreter(subinterpreter const ©) = delete; |
| subinterpreter &operator=(subinterpreter const ©) = delete; |
| |
| subinterpreter(subinterpreter &&old) noexcept |
| : istate_(old.istate_), creation_tstate_(old.creation_tstate_) { |
| old.istate_ = nullptr; |
| old.creation_tstate_ = nullptr; |
| } |
| |
| subinterpreter &operator=(subinterpreter &&old) noexcept { |
| std::swap(old.istate_, istate_); |
| std::swap(old.creation_tstate_, creation_tstate_); |
| return *this; |
| } |
| |
| /// Create a new subinterpreter with the specified configuration |
| /// @note This function acquires (and then releases) the main interpreter GIL, but the main |
| /// interpreter and its GIL are not required to be held prior to calling this function. |
| static inline subinterpreter create(PyInterpreterConfig const &cfg) { |
| |
| error_scope err_scope; |
| subinterpreter result; |
| { |
| // we must hold the main GIL in order to create a subinterpreter |
| subinterpreter_scoped_activate main_guard(main()); |
| |
| auto prev_tstate = PyThreadState_Get(); |
| |
| PyStatus status; |
| |
| { |
| /* |
| Several internal CPython modules are lacking proper subinterpreter support in 3.12 |
| even though it is "stable" in that version. This most commonly seems to cause |
| crashes when two interpreters concurrently initialize, which imports several things |
| (like builtins, unicode, codecs). |
| */ |
| #if PY_VERSION_HEX < 0x030D0000 && defined(Py_MOD_PER_INTERPRETER_GIL_SUPPORTED) |
| static std::mutex one_at_a_time; |
| std::lock_guard<std::mutex> guard(one_at_a_time); |
| #endif |
| status = Py_NewInterpreterFromConfig(&result.creation_tstate_, &cfg); |
| } |
| |
| // this doesn't raise a normal Python exception, it provides an exit() status code. |
| if (PyStatus_Exception(status)) { |
| pybind11_fail("failed to create new sub-interpreter"); |
| } |
| |
| // upon success, the new interpreter is activated in this thread |
| result.istate_ = result.creation_tstate_->interp; |
| detail::get_num_interpreters_seen() += 1; // there are now many interpreters |
| detail::get_internals(); // initialize internals.tstate, amongst other things... |
| |
| // In 3.13+ this state should be deleted right away, and the memory will be reused for |
| // the next threadstate on this interpreter. However, on 3.12 we cannot do that, we |
| // must keep it around (but not use it) ... see destructor. |
| #if PY_VERSION_HEX >= 0x030D0000 |
| PyThreadState_Clear(result.creation_tstate_); |
| PyThreadState_DeleteCurrent(); |
| #endif |
| |
| // we have to switch back to main, and then the scopes will handle cleanup |
| PyThreadState_Swap(prev_tstate); |
| } |
| return result; |
| } |
| |
| /// Calls create() with a default configuration of an isolated interpreter that disallows fork, |
| /// exec, and Python threads. |
| static inline subinterpreter create() { |
| // same as the default config in the python docs |
| PyInterpreterConfig cfg; |
| std::memset(&cfg, 0, sizeof(cfg)); |
| cfg.allow_threads = 1; |
| cfg.check_multi_interp_extensions = 1; |
| cfg.gil = PyInterpreterConfig_OWN_GIL; |
| return create(cfg); |
| } |
| |
| ~subinterpreter() { |
| if (!creation_tstate_) { |
| // non-owning wrapper, do nothing. |
| return; |
| } |
| |
| PyThreadState *destroy_tstate; |
| PyThreadState *old_tstate; |
| |
| // Python 3.12 requires us to keep the original PyThreadState alive until we are ready to |
| // destroy the interpreter. We prefer to use that to destroy the interpreter. |
| #if PY_VERSION_HEX < 0x030D0000 |
| // The tstate passed to Py_EndInterpreter MUST have been created on the current OS thread. |
| bool same_thread = false; |
| # ifdef PY_HAVE_THREAD_NATIVE_ID |
| same_thread = PyThread_get_thread_native_id() == creation_tstate_->native_thread_id; |
| # endif |
| if (same_thread) { |
| // OK it is safe to use the creation state here |
| destroy_tstate = creation_tstate_; |
| old_tstate = PyThreadState_Swap(destroy_tstate); |
| } else { |
| // We have to make a new tstate on this thread and use that. |
| destroy_tstate = PyThreadState_New(istate_); |
| old_tstate = PyThreadState_Swap(destroy_tstate); |
| |
| // We can use the one we just created, so we must delete the creation state. |
| PyThreadState_Clear(creation_tstate_); |
| PyThreadState_Delete(creation_tstate_); |
| } |
| #else |
| destroy_tstate = PyThreadState_New(istate_); |
| old_tstate = PyThreadState_Swap(destroy_tstate); |
| #endif |
| |
| bool switch_back = old_tstate && old_tstate->interp != istate_; |
| |
| // Internals always exists in the subinterpreter, this class enforces it when it creates |
| // the subinterpreter. Even if it didn't, this only creates the pointer-to-pointer, not the |
| // internals themselves. |
| detail::get_internals_pp_manager().get_pp(); |
| detail::get_local_internals_pp_manager().get_pp(); |
| |
| // End it |
| Py_EndInterpreter(destroy_tstate); |
| |
| // It's possible for the internals to be created during endinterpreter (e.g. if a |
| // py::capsule calls `get_internals()` during destruction), so we destroy afterward. |
| detail::get_internals_pp_manager().destroy(); |
| detail::get_local_internals_pp_manager().destroy(); |
| |
| // switch back to the old tstate and old GIL (if there was one) |
| if (switch_back) |
| PyThreadState_Swap(old_tstate); |
| } |
| |
| /// Get a handle to the main interpreter that can be used with subinterpreter_scoped_activate |
| /// Note that destructing the handle is a noop, the main interpreter can only be ended by |
| /// py::finalize_interpreter() |
| static subinterpreter main() { |
| subinterpreter m; |
| m.istate_ = PyInterpreterState_Main(); |
| m.disarm(); // make destruct a noop |
| return m; |
| } |
| |
| /// Get a non-owning wrapper of the currently active interpreter (if any) |
| static subinterpreter current() { |
| subinterpreter c; |
| c.istate_ = detail::get_interpreter_state_unchecked(); |
| c.disarm(); // make destruct a noop, we don't own this... |
| return c; |
| } |
| |
| /// Get the numerical identifier for the sub-interpreter |
| int64_t id() const { |
| if (istate_ != nullptr) |
| return PyInterpreterState_GetID(istate_); |
| else |
| return -1; // CPython uses one-up numbers from 0, so negative should be safe to return |
| // here. |
| } |
| |
| /// Get the interpreter's state dict. This interpreter's GIL must be held before calling! |
| dict state_dict() { return reinterpret_borrow<dict>(PyInterpreterState_GetDict(istate_)); } |
| |
| /// abandon cleanup of this subinterpreter (leak it). this might be needed during |
| /// finalization... |
| void disarm() { creation_tstate_ = nullptr; } |
| |
| /// An empty wrapper cannot be activated |
| bool empty() const { return istate_ == nullptr; } |
| |
| /// Is this wrapper non-empty |
| explicit operator bool() const { return !empty(); } |
| |
| private: |
| friend class subinterpreter_scoped_activate; |
| PyInterpreterState *istate_ = nullptr; |
| PyThreadState *creation_tstate_ = nullptr; |
| }; |
| |
| class scoped_subinterpreter { |
| public: |
| scoped_subinterpreter() : si_(subinterpreter::create()), scope_(si_) {} |
| |
| explicit scoped_subinterpreter(PyInterpreterConfig const &cfg) |
| : si_(subinterpreter::create(cfg)), scope_(si_) {} |
| |
| private: |
| subinterpreter si_; |
| subinterpreter_scoped_activate scope_; |
| }; |
| |
| inline subinterpreter_scoped_activate::subinterpreter_scoped_activate(subinterpreter const &si) { |
| if (!si.istate_) { |
| pybind11_fail("null subinterpreter"); |
| } |
| |
| if (detail::get_interpreter_state_unchecked() == si.istate_) { |
| // we are already on this interpreter, make sure we hold the GIL |
| simple_gil_ = true; |
| gil_state_ = PyGILState_Ensure(); |
| return; |
| } |
| |
| // we can't really interact with the interpreter at all until we switch to it |
| // not even to, for example, look in its state dict or touch its internals |
| tstate_ = PyThreadState_New(si.istate_); |
| |
| // make the interpreter active and acquire the GIL |
| old_tstate_ = PyThreadState_Swap(tstate_); |
| |
| // save this in internals for scoped_gil calls |
| detail::get_internals().tstate = tstate_; |
| } |
| |
| inline subinterpreter_scoped_activate::~subinterpreter_scoped_activate() { |
| if (simple_gil_) { |
| // We were on this interpreter already, so just make sure the GIL goes back as it was |
| PyGILState_Release(gil_state_); |
| } else { |
| if (tstate_) { |
| #if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
| if (detail::get_thread_state_unchecked() != tstate_) { |
| pybind11_fail("~subinterpreter_scoped_activate: thread state must be current!"); |
| } |
| #endif |
| detail::get_internals().tstate.reset(); |
| PyThreadState_Clear(tstate_); |
| PyThreadState_DeleteCurrent(); |
| } |
| |
| // Go back the previous interpreter (if any) and acquire THAT gil |
| PyThreadState_Swap(old_tstate_); |
| } |
| } |
| |
| PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |