@@ -211,6 +211,54 @@ struct internals {
211211#endif
212212};
213213
214+ internals &get_internals ();
215+
216+ // the internals struct (above) is shared between all the modules. local_internals are only
217+ // for a single module. Any changes made to internals may require an update to
218+ // PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
219+ // restricted to a single module. Whether a module has local internals or not should not
220+ // impact any other modules, because the only things accessing the local internals is the
221+ // module that contains them.
222+ struct local_internals {
223+ type_map<type_info *> registered_types_cpp;
224+ std::forward_list<ExceptionTranslator> registered_exception_translators;
225+ #if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
226+
227+ // For ABI compatibility, we can't store the loader_life_support TLS key in
228+ // the `internals` struct directly. Instead, we store it in `shared_data` and
229+ // cache a copy in `local_internals`. If we allocated a separate TLS key for
230+ // each instance of `local_internals`, we could end up allocating hundreds of
231+ // TLS keys if hundreds of different pybind11 modules are loaded (which is a
232+ // plausible number).
233+ PYBIND11_TLS_KEY_INIT (loader_life_support_tls_key)
234+
235+ // Holds the shared TLS key for the loader_life_support stack.
236+ struct shared_loader_life_support_data {
237+ PYBIND11_TLS_KEY_INIT (loader_life_support_tls_key)
238+ shared_loader_life_support_data () {
239+ if (!PYBIND11_TLS_KEY_CREATE (loader_life_support_tls_key)) {
240+ pybind11_fail (" local_internals: could not successfully initialize the "
241+ " loader_life_support TLS key!" );
242+ }
243+ }
244+ // We can't help but leak the TLS key, because Python never unloads extension modules.
245+ };
246+
247+ local_internals () {
248+ auto &internals = get_internals ();
249+ // Get or create the `loader_life_support_stack_key`.
250+ auto &ptr = internals.shared_data [" _life_support" ];
251+ if (!ptr) {
252+ ptr = new shared_loader_life_support_data;
253+ }
254+ loader_life_support_tls_key
255+ = static_cast <shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key ;
256+ }
257+ #endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
258+ };
259+
260+ local_internals &get_local_internals ();
261+
214262// / Additional type information which does not fit into the PyTypeObject.
215263// / Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
216264struct type_info {
@@ -314,16 +362,41 @@ inline internals **&get_internals_pp() {
314362 return internals_pp;
315363}
316364
317- // forward decl
318- inline void translate_exception (std::exception_ptr);
365+ // Apply all the extensions translators from a list
366+ // Return true if one of the translators completed without raising an exception
367+ // itself. Return of false indicates that if there are other translators
368+ // available, they should be tried.
369+ inline bool apply_exception_translators (std::forward_list<ExceptionTranslator> &translators,
370+ std::exception_ptr last_exception) {
371+ for (auto &translator : translators) {
372+ try {
373+ translator (last_exception);
374+ return true ;
375+ } catch (...) {
376+ last_exception = std::current_exception ();
377+ }
378+ }
379+ return false ;
380+ }
381+
382+ inline bool apply_exception_translators (std::forward_list<ExceptionTranslator> &translators) {
383+ return apply_exception_translators (translators, std::current_exception ());
384+ }
319385
320386template <class T ,
321387 enable_if_t <std::is_same<std::nested_exception, remove_cvref_t <T>>::value, int > = 0 >
322388bool handle_nested_exception (const T &exc, const std::exception_ptr &p) {
323389 std::exception_ptr nested = exc.nested_ptr ();
324390 if (nested != nullptr && nested != p) {
325- translate_exception (nested);
326- return true ;
391+ auto &local_translators = get_local_internals ().registered_exception_translators ;
392+ if (apply_exception_translators (local_translators, nested)) {
393+ return true ;
394+ }
395+
396+ auto &translators = get_internals ().registered_exception_translators ;
397+ if (apply_exception_translators (translators, nested)) {
398+ return true ;
399+ }
327400 }
328401 return false ;
329402}
@@ -491,50 +564,6 @@ PYBIND11_NOINLINE internals &get_internals() {
491564 return **internals_pp;
492565}
493566
494- // the internals struct (above) is shared between all the modules. local_internals are only
495- // for a single module. Any changes made to internals may require an update to
496- // PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,
497- // restricted to a single module. Whether a module has local internals or not should not
498- // impact any other modules, because the only things accessing the local internals is the
499- // module that contains them.
500- struct local_internals {
501- type_map<type_info *> registered_types_cpp;
502- std::forward_list<ExceptionTranslator> registered_exception_translators;
503- #if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
504-
505- // For ABI compatibility, we can't store the loader_life_support TLS key in
506- // the `internals` struct directly. Instead, we store it in `shared_data` and
507- // cache a copy in `local_internals`. If we allocated a separate TLS key for
508- // each instance of `local_internals`, we could end up allocating hundreds of
509- // TLS keys if hundreds of different pybind11 modules are loaded (which is a
510- // plausible number).
511- PYBIND11_TLS_KEY_INIT (loader_life_support_tls_key)
512-
513- // Holds the shared TLS key for the loader_life_support stack.
514- struct shared_loader_life_support_data {
515- PYBIND11_TLS_KEY_INIT (loader_life_support_tls_key)
516- shared_loader_life_support_data () {
517- if (!PYBIND11_TLS_KEY_CREATE (loader_life_support_tls_key)) {
518- pybind11_fail (" local_internals: could not successfully initialize the "
519- " loader_life_support TLS key!" );
520- }
521- }
522- // We can't help but leak the TLS key, because Python never unloads extension modules.
523- };
524-
525- local_internals () {
526- auto &internals = get_internals ();
527- // Get or create the `loader_life_support_stack_key`.
528- auto &ptr = internals.shared_data [" _life_support" ];
529- if (!ptr) {
530- ptr = new shared_loader_life_support_data;
531- }
532- loader_life_support_tls_key
533- = static_cast <shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key ;
534- }
535- #endif // defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4
536- };
537-
538567// / Works like `get_internals`, but for things which are locally registered.
539568inline local_internals &get_local_internals () {
540569 // Current static can be created in the interpreter finalization routine. If the later will be
0 commit comments