Skip to content

Conversation

@XuehaiPan
Copy link
Contributor

@XuehaiPan XuehaiPan commented Dec 13, 2025

Description

Fixes #5926

For !defined(PYBIND11_HAS_SUBINTERPRETER_SUPPORT), the previous behavior is unchanged.

For defined(PYBIND11_HAS_SUBINTERPRETER_SUPPORT), the pybind11 internals is already a per-interpreter-dependent singleton stored in the interpreter's state dict. This PR adds a new map to the interpreter-dependent internals from the gil_safe_call_once_and_store's address to the result, where the gil_safe_call_once_and_store is a static object that has a fixed address.

Suggested changelog entry:

  • Add per-interpreter storage for gil_safe_call_once_and_store to make it safe under multi-interpreters.

@XuehaiPan XuehaiPan force-pushed the subinterp-call-once-and-store branch 3 times, most recently from 58834ac to a46973b Compare December 14, 2025 04:07
@XuehaiPan XuehaiPan force-pushed the subinterp-call-once-and-store branch from a46973b to e741760 Compare December 14, 2025 04:08
@XuehaiPan XuehaiPan marked this pull request as ready for review December 14, 2025 06:47
Comment on lines +599 to 608
// FIXME: We cannot use `get_num_interpreters_seen() > 1` here to create a fast path for
// the multi-interpreter case. The singleton may be initialized by a subinterpreter not the
// main interpreter.
//
// For multi-interpreter support, the subinterpreters can be initialized concurrently, and
// the first time this function may not be called in the main interpreter.
// For example, a clean main interpreter that does not import any pybind11 module and then
// spawns multiple subinterpreters using `InterpreterPoolExecutor` that each imports a
// pybind11 module concurrently.
if (get_num_interpreters_seen() > 1) {
Copy link
Contributor Author

@XuehaiPan XuehaiPan Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @b-pass @rwgk for thoughts about this, see the code comment referenced for more details.

I test the patch in this PR in:

Most things works fine except test_import_in_subinterpreter_before_main:

run_in_subprocess(
    """
    with contextlib.closing(interpreters.create()) as subinterpreter:
        subinterpreter.exec('import optree')

    import optree
    """
)

If I remove the get_num_interpreters_seen() > 1 condition, my import test works but the cpptest in pybind11 CI breaks because internals_singleton_pp_ is never initialized. For instance, the memory address get_internals() should be a shared constant for differenet pybind11 modules in a single program.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: pybind11::gil_safe_call_once_and_store is not safe for Python subinterpreters

1 participant