Skip to content

Commit 76564dd

Browse files
committed
Move most of the internals initialization into its constructor.
1 parent 628d40e commit 76564dd

File tree

1 file changed

+48
-38
lines changed

1 file changed

+48
-38
lines changed

include/pybind11/detail/internals.h

+48-38
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ constexpr const char *internals_function_record_capsule_name = "pybind11_functio
5454
inline PyTypeObject *make_static_property_type();
5555
inline PyTypeObject *make_default_metaclass();
5656
inline PyObject *make_object_base_type(PyTypeObject *metaclass);
57+
inline void translate_exception(std::exception_ptr p);
5758

5859
// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new
5960
// Thread Specific Storage (TSS) API.
@@ -179,9 +180,9 @@ struct internals {
179180
// extensions
180181
std::forward_list<std::string> static_strings; // Stores the std::strings backing
181182
// detail::c_str()
182-
PyTypeObject *static_property_type;
183-
PyTypeObject *default_metaclass;
184-
PyObject *instance_base;
183+
PyTypeObject *static_property_type = nullptr;
184+
PyTypeObject *default_metaclass = nullptr;
185+
PyObject *instance_base = nullptr;
185186
// Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:
186187
PYBIND11_TLS_KEY_INIT(tstate)
187188
PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)
@@ -190,7 +191,36 @@ struct internals {
190191

191192
type_map<PyObject *> native_enum_type_map;
192193

193-
internals() = default;
194+
internals() {
195+
PyThreadState *curtstate = PyThreadState_Get();
196+
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
197+
if (!PYBIND11_TLS_KEY_CREATE(tstate)) {
198+
pybind11_fail(
199+
"internals constructor: could not successfully initialize the tstate TSS key!");
200+
}
201+
PYBIND11_TLS_REPLACE_VALUE(tstate, curtstate);
202+
203+
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
204+
if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {
205+
pybind11_fail("internals constructor: could not successfully initialize the "
206+
"loader_life_support TSS key!");
207+
}
208+
209+
istate = curtstate->interp;
210+
registered_exception_translators.push_front(&translate_exception);
211+
static_property_type = make_static_property_type();
212+
default_metaclass = make_default_metaclass();
213+
#ifdef Py_GIL_DISABLED
214+
// Scale proportional to the number of cores. 2x is a heuristic to reduce contention.
215+
auto num_shards
216+
= static_cast<size_t>(round_up_to_next_pow2(2 * std::thread::hardware_concurrency()));
217+
if (num_shards == 0) {
218+
num_shards = 1;
219+
}
220+
instance_shards.reset(new instance_map_shard[num_shards]);
221+
instance_shards_mask = num_shards - 1;
222+
#endif
223+
}
194224
internals(const internals &other) = delete;
195225
internals &operator=(const internals &other) = delete;
196226
~internals() {
@@ -461,18 +491,25 @@ inline InternalsType **get_internals_pp_from_capsule_in_state_dict(dict &state_d
461491
PYBIND11_NOINLINE internals &get_internals() {
462492
auto **&internals_pp = get_internals_pp();
463493
if (internals_pp && *internals_pp) {
494+
// This is the fast path, everything is already setup, just return it
464495
return **internals_pp;
465496
}
466497

498+
// Slow path, something needs fetched from the state dict or created
499+
467500
// Cannot use py::gil_scoped_acquire inside get_internals since that calls get_internals.
468501
gil_scoped_acquire_simple gil;
469502
error_scope err_scope;
470503

471504
dict state_dict = get_python_state_dict();
472505
internals_pp = get_internals_pp_from_capsule_in_state_dict<internals>(state_dict,
473506
PYBIND11_INTERNALS_ID);
507+
if (!internals_pp) {
508+
internals_pp = new internals *(nullptr);
509+
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
510+
}
474511

475-
if (internals_pp && *internals_pp) {
512+
if (*internals_pp) {
476513
// We loaded the internals through `state_dict`, which means that our `error_already_set`
477514
// and `builtin_exception` may be different local classes than the ones set up in the
478515
// initial exception translator, below, so add another for our local exception classes.
@@ -489,43 +526,16 @@ PYBIND11_NOINLINE internals &get_internals() {
489526
}
490527
#endif
491528
} else {
492-
if (!internals_pp) {
493-
internals_pp = new internals *(nullptr);
494-
state_dict[PYBIND11_INTERNALS_ID] = capsule(reinterpret_cast<void *>(internals_pp));
495-
}
496-
497-
auto *&internals_ptr = *internals_pp;
529+
auto &internals_ptr = *internals_pp;
498530
internals_ptr = new internals();
499531

500-
PyThreadState *tstate = PyThreadState_Get();
501-
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
502-
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {
503-
pybind11_fail("get_internals: could not successfully initialize the tstate TSS key!");
532+
if (!internals_ptr->instance_base) {
533+
// This calls get_internals, so cannot be called from within the internals constructor
534+
// called above because internals_ptr must be set before get_internals is called again
535+
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
504536
}
505-
PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);
506-
507-
// NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
508-
if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {
509-
pybind11_fail("get_internals: could not successfully initialize the "
510-
"loader_life_support TSS key!");
511-
}
512-
513-
internals_ptr->istate = tstate->interp;
514-
internals_ptr->registered_exception_translators.push_front(&translate_exception);
515-
internals_ptr->static_property_type = make_static_property_type();
516-
internals_ptr->default_metaclass = make_default_metaclass();
517-
internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);
518-
#ifdef Py_GIL_DISABLED
519-
// Scale proportional to the number of cores. 2x is a heuristic to reduce contention.
520-
auto num_shards
521-
= static_cast<size_t>(round_up_to_next_pow2(2 * std::thread::hardware_concurrency()));
522-
if (num_shards == 0) {
523-
num_shards = 1;
524-
}
525-
internals_ptr->instance_shards.reset(new instance_map_shard[num_shards]);
526-
internals_ptr->instance_shards_mask = num_shards - 1;
527-
#endif // Py_GIL_DISABLED
528537
}
538+
529539
return **internals_pp;
530540
}
531541

0 commit comments

Comments
 (0)