|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
}; |
|
|
|
|
|
|
|
|
class subinterpreter { |
|
|
public: |
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline subinterpreter create(PyInterpreterConfig const &cfg) { |
|
|
|
|
|
error_scope err_scope; |
|
|
subinterpreter result; |
|
|
{ |
|
|
|
|
|
subinterpreter_scoped_activate main_guard(main()); |
|
|
|
|
|
auto prev_tstate = PyThreadState_Get(); |
|
|
|
|
|
PyStatus status; |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#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); |
|
|
} |
|
|
|
|
|
|
|
|
if (PyStatus_Exception(status)) { |
|
|
pybind11_fail("failed to create new sub-interpreter"); |
|
|
} |
|
|
|
|
|
|
|
|
result.istate_ = result.creation_tstate_->interp; |
|
|
detail::get_num_interpreters_seen() += 1; |
|
|
detail::get_internals(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if PY_VERSION_HEX >= 0x030D0000 |
|
|
PyThreadState_Clear(result.creation_tstate_); |
|
|
PyThreadState_DeleteCurrent(); |
|
|
#endif |
|
|
|
|
|
|
|
|
PyThreadState_Swap(prev_tstate); |
|
|
} |
|
|
return result; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline subinterpreter create() { |
|
|
|
|
|
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_) { |
|
|
|
|
|
return; |
|
|
} |
|
|
|
|
|
PyThreadState *destroy_tstate; |
|
|
PyThreadState *old_tstate; |
|
|
|
|
|
|
|
|
|
|
|
#if PY_VERSION_HEX < 0x030D0000 |
|
|
|
|
|
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) { |
|
|
|
|
|
destroy_tstate = creation_tstate_; |
|
|
old_tstate = PyThreadState_Swap(destroy_tstate); |
|
|
} else { |
|
|
|
|
|
destroy_tstate = PyThreadState_New(istate_); |
|
|
old_tstate = PyThreadState_Swap(destroy_tstate); |
|
|
|
|
|
|
|
|
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_; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
detail::get_internals_pp_manager().get_pp(); |
|
|
detail::get_local_internals_pp_manager().get_pp(); |
|
|
|
|
|
|
|
|
Py_EndInterpreter(destroy_tstate); |
|
|
|
|
|
|
|
|
|
|
|
detail::get_internals_pp_manager().destroy(); |
|
|
detail::get_local_internals_pp_manager().destroy(); |
|
|
|
|
|
|
|
|
if (switch_back) |
|
|
PyThreadState_Swap(old_tstate); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static subinterpreter main() { |
|
|
subinterpreter m; |
|
|
m.istate_ = PyInterpreterState_Main(); |
|
|
m.disarm(); |
|
|
return m; |
|
|
} |
|
|
|
|
|
|
|
|
static subinterpreter current() { |
|
|
subinterpreter c; |
|
|
c.istate_ = detail::get_interpreter_state_unchecked(); |
|
|
c.disarm(); |
|
|
return c; |
|
|
} |
|
|
|
|
|
|
|
|
int64_t id() const { |
|
|
if (istate_ != nullptr) |
|
|
return PyInterpreterState_GetID(istate_); |
|
|
else |
|
|
return -1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
dict state_dict() { return reinterpret_borrow<dict>(PyInterpreterState_GetDict(istate_)); } |
|
|
|
|
|
|
|
|
|
|
|
void disarm() { creation_tstate_ = nullptr; } |
|
|
|
|
|
|
|
|
bool empty() const { return istate_ == nullptr; } |
|
|
|
|
|
|
|
|
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_) { |
|
|
|
|
|
simple_gil_ = true; |
|
|
gil_state_ = PyGILState_Ensure(); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
tstate_ = PyThreadState_New(si.istate_); |
|
|
|
|
|
|
|
|
old_tstate_ = PyThreadState_Swap(tstate_); |
|
|
|
|
|
|
|
|
detail::get_internals().tstate = tstate_; |
|
|
} |
|
|
|
|
|
inline subinterpreter_scoped_activate::~subinterpreter_scoped_activate() { |
|
|
if (simple_gil_) { |
|
|
|
|
|
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(); |
|
|
} |
|
|
|
|
|
|
|
|
PyThreadState_Swap(old_tstate_); |
|
|
} |
|
|
} |
|
|
|
|
|
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
|
|
|