Re-enable Move Subinterpreter test for free-threaded Python 3.14 (#5940)

* Remove skip for Move Subinterpreter test on free-threaded Python 3.14+

* Fix deadlock by detaching from the main interpreter before joining the thread.

* style: pre-commit fixes

---------

Co-authored-by: b-pass <b-pass@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Ralf W. Grosse-Kunstleve
2025-12-23 12:32:41 +07:00
committed by GitHub
parent 7ae61bfb82
commit 799f591ec3
2 changed files with 13 additions and 9 deletions

View File

@@ -492,4 +492,8 @@ Best Practices for sub-interpreter safety
So you must still consider the thread safety of your C++ code. Remember, in Python 3.12
sub-interpreters must be destroyed on the same thread that they were created on.
- When using sub-interpreters in free-threaded python builds, note that creating and destroying
sub-interpreters may initiate a "stop-the-world". Be sure to detach long-running C++ threads
from Python thread state (similar to releasing the GIL) to avoid deadlocks.
- Familiarize yourself with :ref:`misc_concurrency`.

View File

@@ -94,13 +94,6 @@ TEST_CASE("Single Subinterpreter") {
# if PY_VERSION_HEX >= 0x030D0000
TEST_CASE("Move Subinterpreter") {
// Test is skipped on free-threaded Python 3.14+ due to a hang in Py_EndInterpreter()
// when the subinterpreter is destroyed from a different thread than it was created on.
// See: https://github.com/pybind/pybind11/pull/5940
# if PY_VERSION_HEX >= 0x030E0000 && defined(Py_GIL_DISABLED)
PYBIND11_CATCH2_SKIP_IF(true, "Skipped on free-threaded Python 3.14+ (see PR #5940)");
# endif
std::unique_ptr<py::subinterpreter> sub(new py::subinterpreter(py::subinterpreter::create()));
// on this thread, use the subinterpreter and import some non-trivial junk
@@ -113,14 +106,21 @@ TEST_CASE("Move Subinterpreter") {
py::module_::import("external_module");
}
std::thread([&]() {
auto t = std::thread([&]() {
// Use it again
{
py::subinterpreter_scoped_activate activate(*sub);
py::module_::import("external_module");
}
sub.reset();
}).join();
});
// on 3.14.1+ destructing a sub-interpreter does a stop-the-world. we need to detach our
// thread state in order for that to be possible.
{
py::gil_scoped_release nogil;
t.join();
}
REQUIRE(!sub);