@@ -211,6 +211,54 @@ struct internals {
211
211
#endif
212
212
};
213
213
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
+
214
262
// / Additional type information which does not fit into the PyTypeObject.
215
263
// / Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
216
264
struct type_info {
@@ -314,16 +362,41 @@ inline internals **&get_internals_pp() {
314
362
return internals_pp;
315
363
}
316
364
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
+ }
319
385
320
386
template <class T ,
321
387
enable_if_t <std::is_same<std::nested_exception, remove_cvref_t <T>>::value, int > = 0 >
322
388
bool handle_nested_exception (const T &exc, const std::exception_ptr &p) {
323
389
std::exception_ptr nested = exc.nested_ptr ();
324
390
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
+ }
327
400
}
328
401
return false ;
329
402
}
@@ -491,50 +564,6 @@ PYBIND11_NOINLINE internals &get_internals() {
491
564
return **internals_pp;
492
565
}
493
566
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
-
538
567
// / Works like `get_internals`, but for things which are locally registered.
539
568
inline local_internals &get_local_internals () {
540
569
// Current static can be created in the interpreter finalization routine. If the later will be
0 commit comments