@@ -697,33 +697,37 @@ class internals_pp_manager {
697697 // this could be called without an active interpreter, just use what was cached
698698 if (!tstate || tstate->interp == last_istate_tls ()) {
699699 auto tpp = internals_p_tls ();
700- pps_have_created_content_.erase (tpp);
701- delete tpp;
700+ {
701+ std::lock_guard<std::mutex> lock (pps_creation_mutex_);
702+ pps_have_created_content_.erase (tpp);
703+ delete tpp;
704+ }
702705 }
703706 unref ();
704707 return ;
705708 }
706709#endif
707- pps_have_created_content_.erase (internals_singleton_pp_);
708- delete internals_singleton_pp_;
710+ {
711+ std::lock_guard<std::mutex> lock (pps_creation_mutex_);
712+ pps_have_created_content_.erase (internals_singleton_pp_);
713+ delete internals_singleton_pp_;
714+ }
709715 unref ();
710716 }
711717
712718 void create_pp_content_once (std::unique_ptr<InternalsType> *pp) {
713719 // Assume the GIL is held
714720 {
715- #ifndef Py_GIL_DISABLED
716- const gil_scoped_release_simple gil_release{};
717- #endif
718- static std::mutex mtx;
719- std::lock_guard<std::mutex> lock (mtx);
721+ std::lock_guard<std::mutex> lock (pps_creation_mutex_);
720722
721723 // Prevent re-creation of internals after destruction during interpreter shutdown.
722724 // If pybind11 code (e.g., tp_traverse/tp_clear calling py::cast) runs after internals
723725 // have been destroyed, a new empty internals would be created, causing type lookup
724726 // failures. See https://github.com/pybind/pybind11/pull/5958#discussion_r2717645230.
725727 if (pps_have_created_content_.find (pp) != pps_have_created_content_.end ()) {
726- pybind11_fail (" Reentrant call detected while fetching pybind11 internals!" );
728+ pybind11_fail (
729+ " pybind11::detail::internals_pp_manager::create_pp_content_once() FAILED: "
730+ " reentrant call detected while fetching pybind11 internals!" );
727731 }
728732 // Each pp can only create its internals once.
729733 pps_have_created_content_.insert (pp);
@@ -776,7 +780,8 @@ class internals_pp_manager {
776780
777781 // Tracks pointer-to-pointers whose internals have been created, to detect re-entrancy.
778782 // Use instance member over static due to singleton pattern of this class.
779- std::unordered_set<void *> pps_have_created_content_;
783+ std::unordered_set<std::unique_ptr<InternalsType> *> pps_have_created_content_;
784+ std::mutex pps_creation_mutex_;
780785};
781786
782787// If We loaded the internals through `state_dict`, our `error_already_set`
0 commit comments