Commit Graph

11 Commits

Author SHA1 Message Date
Xuehai Pan
3ae5a173c5 Add fallback implementation of PyCriticalSection_BeginMutex for Python 3.13t (#5981)
* Add failback implementation of `PyCriticalSection_BeginMutex` for Python 3.13t

* Add comment for Python version

* Use `_PyCriticalSection_BeginSlow`

* Add forward declaration

* Fix forward declaration

* Remove always true condition `defined(PY_VERSION_HEX)`

* Detect musllinux

* Add manylinux test

* Use direct mutex locking for Python 3.13t

`_PyCriticalSection_BeginSlow` is a private CPython function not exported
on Linux. For Python < 3.14.0rc1, use direct `mutex.lock()`/`mutex.unlock()`
instead of critical section APIs.

* Empty commit to trigger CI

* Empty commit to trigger CI

* Empty commit to trigger CI

* Run apt update before apt install

* Remove unnecessary prefix

* Add manylinux test with Python 3.13t

* Simplify pycritical_section with std::unique_lock fallback for Python < 3.14

* Fix potential deadlock in make_iterator_impl for Python 3.13t

Refactor pycritical_section into a unified class with internal version
checks instead of using a type alias fallback. Skip locking in
make_iterator_impl for Python < 3.14.0rc1 to avoid deadlock during
type registration, as pycritical_section cannot release the mutex
during Python callbacks without PyCriticalSection_BeginMutex.

* Add reference for xfail message
2026-02-09 21:14:07 -08:00
Xuehai Pan
e7754de037 Revert internals destruction and add test for internals recreation (#5972)
* Bump internals version

* Prevent internals destruction before all pybind11 types are destroyed

* Use Py_XINCREF and Py_XDECREF

* Hold GIL before decref

* Use weakrefs

* Remove unused code

* Move code location

* Move code location

* Move code location

* Try add tests

* Fix PYTHONPATH

* Fix PYTHONPATH

* Skip tests for subprocess

* Revert to leak internals

* Revert to leak internals

* Revert "Revert to leak internals"

This reverts commit c5ec1cf886.
This reverts commit 72c2e0aa9b.

* Revert internals version bump

* Reapply to leak internals

This reverts commit 8f25a254e8.

* Add re-entrancy detection for internals creation

Prevent re-creation of internals after destruction during interpreter
shutdown. If pybind11 code runs after internals have been destroyed,
fail early with a clear error message instead of silently creating
new empty internals that would cause type lookup failures.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix C++11/C++14 support

* Add lock under multiple interpreters

* Try fix tests

* Try fix tests

* Try fix tests

* Update comments and assertion messages

* Update comments and assertion messages

* Update comments

* Update lock scope

* Use original pointer type for Windows

* Change hard error to warning

* Update lock scope

* Update lock scope to resolve deadlock

* Remove scope release of GIL

* Update comments

* Lock pp on reset

* Mark content created after assignment

* Update comments

* Simplify implementation

* Update lock scope when delete unique_ptr

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:54:05 -08:00
Ralf W. Grosse-Kunstleve
b93c0f7ed8 Fix ambiguous str(handle) constructor for object-derived types (#5949)
* Fix ambiguous `str(handle)` constructor for object-derived types

Templatize `str(handle h)` with SFINAE to exclude types derived from
`object`, resolving ambiguity with `str(const object&)` when calling
`py::str()` on types like `kwargs`, `dict`, etc.

The template now only accepts `handle` or `PyObject*`, while all
`object`-derived types use the `str(const object&)` overload.

* fix(tests): CIBW test fixes from b-pass→vectorcall branch

- Install multiple-interpreter test modules into wheel (CMakeLists.txt)
  The mod_per_interpreter_gil, mod_shared_interpreter_gil, and
  mod_per_interpreter_gil_with_singleton modules were being built
  but not installed into the wheel when using scikit-build-core.

- Pin numpy 2.4.0 for Python 3.14 CI tests (requirements.txt)
  NumPy 2.4.0 is the first version with official Python 3.14 wheels.

- Add IOS platform constant to tests/env.py

- Skip subinterpreter tests on iOS (test_multiple_interpreters.py)
  Subinterpreters are not supported in the iOS simulator environment.

- Enable pytest timeout of 120s for CIBW tests (pyproject.toml)
  Provides a safety net to catch hanging tests before CI job timeout.

- Disable pytest-timeout for Pyodide (no signal.setitimer)
  Pyodide runs in WebAssembly without POSIX signals.

- Add -v flag for verbose pytest output in CIBW tests
2025-12-30 04:54:44 -08:00
Xuehai Pan
fee2527dfa Fix concurrency consistency for internals_pp_manager under multiple-interpreters (#5947)
* Add per-interpreter storage for `gil_safe_call_once_and_store`

* Disable thread local cache for `internals_pp_manager`

* Disable thread local cache for `internals_pp_manager` for multi-interpreter only

* Use anonymous namespace to separate these type_ids from other tests with the same class names.

* style: pre-commit fixes

* Revert internals_pp_manager changes

* This is the crux of fix for the subinterpreter_before_main failure.

The pre_init needs to check if it is in a subinterpreter or not. But in 3.13+ this static initializer runs in the main interpreter.  So we need to check this later, during the exec phase.

* Continue to do the ensure in both places, there might be a reason it was where it was...

Should not hurt anything to do it extra times here.

* Change get_num_interpreters_seen to a boolean flag instead.

The count was not used, it was just checked for > 1, we now accomplish this by setting the flag.

* Spelling typo

* Work around older python versions, only need this check for newish versions

* Add more comments for test case

* Add more comments for test case

* Stop traceback propagation

* Re-enable subinterpreter support on ubuntu 3.14 builds

Was disabled in e4873e8

* As suggested, don't use an anonymous namespace.

* Typo in test assert format string

* Use a more appropriate function name

* Fix mod_per_interpreter_gil* output directory on Windows/MSVC

On Windows with MSVC (multi-configuration generators), CMake uses
config-specific properties like LIBRARY_OUTPUT_DIRECTORY_DEBUG when
set, otherwise falls back to LIBRARY_OUTPUT_DIRECTORY/<Config>/.

The main test modules (pybind11_tests, etc.) correctly set both
LIBRARY_OUTPUT_DIRECTORY and the config-specific variants (lines
517-528), so they output directly to tests/.

However, the mod_per_interpreter_gil* modules only copied the base
LIBRARY_OUTPUT_DIRECTORY property, causing them to be placed in
tests/Debug/ instead of tests/.

This mismatch caused test_import_in_subinterpreter_concurrently and
related tests to fail with ModuleNotFoundError on Windows Python 3.14,
because the test code sets sys.path based on pybind11_tests.__file__
(which is in tests/) but tries to import mod_per_interpreter_gil_with_singleton
(which ended up in tests/Debug/).

This bug was previously masked by @pytest.mark.xfail decorators on
these tests. Now that the underlying "Duplicate C++ type registration"
issue is fixed and the xfails are removed, this path issue surfaced.

The fix mirrors the same pattern used for main test targets: also set
LIBRARY_OUTPUT_DIRECTORY_<CONFIG> for each configuration type.

* Remove unneeded `pytest.importorskip`

* Remove comment

---------

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>
Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
2025-12-26 13:59:11 -05:00
Xuehai Pan
0057e4945d Add per-interpreter storage for gil_safe_call_once_and_store (#5933)
* Add new argument to `gil_safe_call_once_and_store::call_once_and_store_result`

* Add per-interpreter storage for `gil_safe_call_once_and_store`

* Make `~gil_safe_call_once_and_store` a no-op

* Fix C++11 compatibility

* Improve thread-safety and add default finalizer

* Try fix thread-safety

* Try fix thread-safety

* Add a warning comment

* Simplify `PYBIND11_INTERNALS_VERSION >= 12`

* Try fix thread-safety

* Try fix thread-safety

* Revert get_pp()

* Update comments

* Move call-once storage out of internals

* Revert internal version bump

* Cleanup outdated comments

* Move atomic_bool alias into pybind11::detail namespace

The `using atomic_bool = ...` declaration was at global scope,
polluting the global namespace. Move it into pybind11::detail
to avoid potential conflicts with user code.

* Add explicit #include <unordered_map> for subinterpreter support

The subinterpreter branch uses std::unordered_map but relied on
transitive includes. Add an explicit include for robustness.

* Remove extraneous semicolon after destructor definition

Style fix: remove trailing semicolon after ~call_once_storage()
destructor body.

* Add comment explaining unused finalize parameter

Clarify why the finalize callback parameter is intentionally ignored
when subinterpreter support is disabled: the storage is process-global
and leaked to avoid destructor calls after interpreter finalization.

* Add comment explaining error_scope usage

Clarify why error_scope is used: to preserve any existing Python
error state that might be cleared or modified by dict_getitemstringref.

* Improve exception safety in get_or_create_call_once_storage_map()

Use std::unique_ptr to hold the newly allocated storage map until
the capsule is successfully created. This prevents a memory leak
if capsule creation throws an exception.

* Add timeout-minutes: 3 to cpptest workflow steps

Add a 3-minute timeout to all C++ test (cpptest) steps across all
platforms to detect hangs early. This uses GitHub Actions' built-in
timeout-minutes property which works on Linux, macOS, and Windows.

* Add progress reporter for test_with_catch Catch2 runner

Add a custom Catch2 streaming reporter that prints one line per test
case as it starts and ends, with immediate flushing to keep CI logs
current. This makes it easy to see where the embedded/interpreter
tests are spending time and to pinpoint which test case is stuck
when builds hang (e.g., free-threading issues).

The reporter:
- Prints "[ RUN      ]" when each test starts
- Prints "[       OK ]" or "[  FAILED  ]" when each test ends
- Prints the Python version once at the start via Py_GetVersion()
- Uses StreamingReporterBase for immediate output (not buffered)
- Is set as the default reporter via CATCH_CONFIG_DEFAULT_REPORTER

This approach gives visibility into all tests without changing their
behavior, turning otherwise opaque 90-minute CI timeouts into
locatable issues in the Catch output.

* clang-format auto-fix (overlooked before)

* Disable "Move Subinterpreter" test on free-threaded Python 3.14+

This test hangs in Py_EndInterpreter() when the subinterpreter is
destroyed from a different thread than it was created on.

The hang was observed:
- Intermittently on macOS with Python 3.14.0t
- Predictably on macOS, Ubuntu, and Windows with Python 3.14.1t and 3.14.2t

Root cause analysis points to an interaction between pybind11's
subinterpreter creation code and CPython's free-threaded runtime,
specifically around PyThreadState_Swap() after PyThreadState_DeleteCurrent().

See detailed analysis: https://github.com/pybind/pybind11/pull/5933

* style: pre-commit fixes

* Add test for gil_safe_call_once_and_store per-interpreter isolation

This test verifies that gil_safe_call_once_and_store provides separate
storage for each interpreter when subinterpreter support is enabled.

The test caches the interpreter ID in the main interpreter, then creates
a subinterpreter and verifies it gets its own cached value (not the main
interpreter's). Without per-interpreter storage, the subinterpreter would
incorrectly see the main interpreter's cached object.

* Add STARTING/DONE timestamps to test_with_catch output

Print UTC timestamps at the beginning and end of the test run to make
it immediately clear when tests started and whether they ran to
completion. The DONE message includes the Catch session result value.

Example output:
  [ STARTING ] 2025-12-21 03:23:20.497Z
  [ PYTHON   ] 3.14.2 ...
  [ RUN      ] Threads
  [       OK ] Threads
  [ DONE     ] 2025-12-21 03:23:20.512Z (result 0)

* Disable stdout buffering in test_with_catch

Ensure test output appears immediately in CI logs by disabling stdout
buffering. Without this, output may be lost if the process is killed
by a timeout, making it difficult to diagnose which test was hanging.

* EXPERIMENT: Re-enable hanging test to verify CI log buffering fix

This is a temporary commit to verify that the unbuffered stdout fix
makes the hanging test visible in CI logs. REVERT THIS COMMIT after
confirming the output appears.

* Revert "Disable stdout buffering in test_with_catch"

This reverts commit 0f8f32a92a.

* Use USES_TERMINAL for cpptest to show output immediately

Ninja buffers subprocess output until completion. When a test hangs,
the output is never shown, making it impossible to diagnose which test
is hanging. USES_TERMINAL gives the command direct terminal access,
bypassing ninja's buffering.

This explains why Windows CI showed test progress but Linux/macOS did
not - Windows uses MSBuild which doesn't buffer the same way.

* Fix clang-tidy performance-avoid-endl warning

Use '\n' instead of std::endl since USES_TERMINAL now handles
output buffering at the CMake level.

* Add SIGTERM handler to show when test is killed by timeout

When a test hangs and is killed by `timeout`, Catch2 marks it as failed
but the process exits before printing [ DONE ]. This made it unclear
whether the test failed normally or was terminated.

The signal handler prints a clear message when SIGTERM is received,
making timeout-related failures obvious in CI logs.

* Fix typo: atleast -> at_least

* Fix GCC warn_unused_result error for write() in signal handler

Assign the return value to a variable to satisfy GCC's warn_unused_result
attribute, then cast to void to suppress unused variable warning.

* Add USES_TERMINAL to other C++ test targets

Apply the same ninja output buffering fix to test_cross_module_rtti
and test_pure_cpp targets. Also add explanatory comments to all
USES_TERMINAL usages.

* Revert "EXPERIMENT: Re-enable hanging test to verify CI log buffering fix"

This reverts commit a3abdeea89.

* Update comment to reference PR #5940 for Move Subinterpreter fix

* Add alias `interpid_t = std::int64_t`

* Add isolation and gc test for `gil_safe_call_once_and_store`

* Add thread local cache for gil_safe_call_once_and_store

* Revert "Add thread local cache for gil_safe_call_once_and_store"

This reverts commit 5d6681956d2d326fe74c7bf80e845c8e8ddb2a7c.

* Revert changes according to code review

* Relocate multiple-interpreters tests

* Add more tests for multiple interpreters

* Remove copy constructor

* Apply suggestions from code review

* Refactor to use per-storage capsule instead

* Update comments

* Update singleton tests

* Use interpreter id type for `get_num_interpreters_seen()`

* Suppress unused variable warning

* HACKING

* Revert "HACKING"

This reverts commit 534235ea55.

* Try fix concurrency

* Test even harder

* Reorg code to avoid duplicates

* Fix unique_ptr::reset -> unique_ptr::release

* Extract reusable functions

* Fix indentation

* Appease warnings for MSVC

* Appease warnings for MSVC

* Appease warnings for MSVC

* Try fix concurrency by not using `get_num_interpreters_seen() > 1`

* Try fix tests

* Make Python path handling more robust

* Update comments and assertion messages

* Revert changes according to code review

* Disable flaky tests

* Use `@pytest.mark.xfail` rather than `pytest.skip`

* Retrigger CI

* Retrigger CI

* Revert file moves

* Refactor atomic_get_or_create_in_state_dict: improve API and fix on_fetch_ bug

Three improvements to atomic_get_or_create_in_state_dict:

1. Return std::pair<Payload*, bool> instead of just Payload*
   - The bool indicates whether storage was newly created (true) or
     already existed (false), following std::map::insert convention.
   - This fixes a bug where on_fetch_ was called even for newly created
     internals, when it should only run for fetched (existing) ones.
     (Identified by @b-pass in code review)

2. Change LeakOnInterpreterShutdown from template param to runtime arg
   - Renamed to `clear_destructor` to describe what it does locally,
     rather than embedding assumptions about why it's used.
   - Reduces template instantiations (header-only library benefits).
   - The check is in the slow path (create) anyway, so negligible cost.

3. Remove unnecessary braces around the fast-path lookup
   - The braces created a nested scope but declared no local variables
     that would benefit from scoping.

* Remove unused PYBIND11_MULTIPLE_INTERPRETERS_TEST_FILES variable

This variable was defined but never used.

---------

Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-12-24 23:33:02 -08:00
Michael Šimáček
c60c14991d tests: handle 3.12 and 3.13 implementations and 3.14.0b3+ (#5732)
* Use pytest.importorskip to get _xxsubinterpreters

* tests: use modern interpreter API

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: try to fix beta2

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: remove debug printout

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: drop useless checks

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: improve check for 3.14.0b3 and b4+

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* style: pre-commit fixes

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-06-18 18:51:27 -04:00
Henry Schreiner
9295c4a568 fix: follow rest of pybind11 closer with PYBIND11_HAS_SUBINTERPRETER_SUPPORT (#5710)
* fix: follow rest of pybind11 closer with PYBIND11_HAS_SUBINTERPRETER_SUPPORT

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* style: pre-commit fixes

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-06-02 16:08:40 -04:00
Henry Schreiner
e4873e8f59 fix: allow subinterp support to be disabled
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-05-31 15:44:42 -04:00
Henry Schreiner
1c10d5e9b1 fix: prepare for 3.14 beta 2 (#5697)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
2025-05-27 00:05:19 -04:00
Henry Schreiner
094343c74a fix: support Python 3.14 (#5646)
* ci: support Python 3.14

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: Python 3.14 name change

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: fix expected output to handle Python 3.14

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: tighten CLI and add color on 3.14+

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: ignore failure on 3.14.0b1

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: support Python 3.14.0b1 with interperters

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Update test_multiple_interpreters.py

* Update test_multiple_interpreters.py

* fix: new breakage for 3.14 fixed

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: handle empty annotations 3.14

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: Python 3.14 may not create the annotations dict

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: use PyUnstable_IsImmortal

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: use sys._is_immortal

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* tests: ignore large values for refcount too

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* style: pre-commit fixes

* ci: enable all free-threaded builds

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: patch for embed

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Revert "fix: patch for embed"

This reverts commit c4226a0671.

* ci: drop new 3.xt additions

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* fix: logic issue, also add some comments

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Update include/pybind11/pytypes.h

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-05-16 21:58:43 -04:00
b-pass
95e8f89be1 Support for sub-interpreters (#5564)
* Allow per-interpreter internals/local_internals

* Significant rewrite to avoid using thread_locals as much as possible.

Since we can avoid them by checking this atomic, the cmake config conditional shouldn't be necessary.

The slower path (with thread_locals and extra checks) only comes in when a second interpreter is actually instanciated.

* Add a test for per-interpreter GIL

Uses two extra threads to demonstrate that neither shares a GIL.

* Fix for nonconforming std::atomic constructors on some compilers

* style: pre-commit fixes

* Fix initializer to make MSVC happy.

* Switch to gil_scoped_acquire_simple, get rid of old copy of it from internals.h

* Use the PyThreadState's interp member rather than the thread state itself.

* Be more explicit about the type of the internalspp

* Suggested renamings and rewordings

* Rename find_internals_pp and change it to take in the state dict reference

* Use the old raise_from instead of pybind11_fail

* Move most of the internals initialization into its constructor.

* Move round_up_to_next_pow2 function upwards

* Remove redundant forward decl

* Add a python-driven subinterpreter test

* Disable the python subinterpreter test on emscripten

Can't load the native-built cpp modules.

* Switch the internals pointer pointer to a unique_ptr pointer

* Spelling

* Fix clang-tidy warning, compare pointer to nullptr

* Rename get_interpreter_counter to get_num_interpreters_seen

* Try simplifying the test's cmake set_target_properties

* Replace mod_* tags with a single tag w/enum

Update tests accordingly

* Add a test for shared-GIL (legacy) subinterpreters

* Update test to work around differences in the various versions of interpreters modules

* Fix unused parameter

* Rename tests and associated test modules.

* Switch get_internals_pp to a template function

* Rename curtstate to cur_tstate

* refactor: use simpler names

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* style: pre-commit fixes

* fix: return class, not enum

Co-authored-by: Ralf W. Grosse-Kunstleve <rwgkio@gmail.com>
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

* Have to join these threads to make sure they are totally done before the test returns.

* Wrap module_def initialization in a static so it only happens once.

If it happens concurrently in multiple threads, badness ensues....

* style: pre-commit fixes

---------

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Ralf W. Grosse-Kunstleve <rwgkio@gmail.com>
2025-05-14 00:59:44 -07:00