@@ -60,7 +60,7 @@ class gil_safe_call_once_and_store {
6060 // PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called.
6161 template <typename Callable>
6262 gil_safe_call_once_and_store &call_once_and_store_result (Callable &&fn,
63- void (*finalize_fn )(T &) = nullptr ) {
63+ void (*)(T &) /* unused */ ) {
6464
6565 if (!is_initialized_) { // This read is guarded by the GIL.
6666 // Multiple threads may enter here, because the GIL is released in the next line and
@@ -69,9 +69,8 @@ class gil_safe_call_once_and_store {
6969 std::call_once (once_flag_, [&] {
7070 // Only one thread will ever enter here.
7171 gil_scoped_acquire gil_acq;
72- ::new (storage_) T (fn ()); // fn may release, but will reacquire, the GIL.
73- finalize_fn_ = finalize_fn; // Store the finalizer.
74- is_initialized_ = true ; // This write is guarded by the GIL.
72+ ::new (storage_) T (fn ()); // fn may release, but will reacquire, the GIL.
73+ is_initialized_ = true ; // This write is guarded by the GIL.
7574 });
7675 // All threads will observe `is_initialized_` as true here.
7776 }
@@ -92,17 +91,15 @@ class gil_safe_call_once_and_store {
9291 }
9392
9493 constexpr gil_safe_call_once_and_store () = default;
95- PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store () {
96- if (is_initialized_ && finalize_fn_ != nullptr ) {
97- finalize_fn_ (*reinterpret_cast <T *>(storage_));
98- }
99- }
94+ // The instance is a global static, so its destructor runs when the process
95+ // is terminating. Therefore, do nothing here because the Python interpreter
96+ // may have been finalized already.
97+ PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store () = default ;
10098
10199private:
102100 // Global static storage (per process) when subinterpreter support is disabled.
103101 alignas (T) char storage_[sizeof(T)] = {};
104102 std::once_flag once_flag_;
105- void (*finalize_fn_)(T &) = nullptr;
106103
107104 // The `is_initialized_`-`storage_` pair is very similar to `std::optional`,
108105 // but the latter does not have the triviality properties of former,
@@ -124,19 +121,19 @@ class gil_safe_call_once_and_store {
124121 if (!is_initialized_by_atleast_one_interpreter_
125122 || detail::get_num_interpreters_seen () > 1 ) {
126123 detail::with_internals ([&](detail::internals &internals) {
127- const void *key = reinterpret_cast <const void *>(this );
124+ const void *k = reinterpret_cast <const void *>(this );
128125 auto &storage_map = internals.call_once_storage_map ;
129- auto it = storage_map.find (key );
126+ auto it = storage_map.find (k );
130127 if (it == storage_map.end ()) {
131128 gil_scoped_release gil_rel; // Needed to establish lock ordering.
132129 {
133130 // Only one thread will ever enter here.
134131 gil_scoped_acquire gil_acq;
135- auto s = new detail::call_once_storage<T>{};
136- ::new (s ->storage ) T (fn ()); // fn may release, but will reacquire, the GIL.
137- s ->finalize = finalize_fn;
138- last_storage_ = reinterpret_cast <T *>(s ->storage );
139- storage_map.emplace (key, s );
132+ auto v = new detail::call_once_storage<T>{};
133+ ::new (v ->storage ) T (fn ()); // fn may release, but will reacquire, the GIL.
134+ v ->finalize = finalize_fn;
135+ last_storage_ = reinterpret_cast <T *>(v ->storage );
136+ storage_map.emplace (k, v );
140137 };
141138 }
142139 is_initialized_by_atleast_one_interpreter_ = true ;
@@ -153,32 +150,21 @@ class gil_safe_call_once_and_store {
153150 if (!is_initialized_by_atleast_one_interpreter_
154151 || detail::get_num_interpreters_seen () > 1 ) {
155152 detail::with_internals ([&](detail::internals &internals) {
156- const void *key = reinterpret_cast <const void *>(this );
153+ const void *k = reinterpret_cast <const void *>(this );
157154 auto &storage_map = internals.call_once_storage_map ;
158- auto it = storage_map.find (key);
159- assert (it != storage_map.end ());
160- auto *s = static_cast <detail::call_once_storage<T> *>(it->second );
161- result = last_storage_ = reinterpret_cast <T *>(s->storage );
155+ auto *v = static_cast <detail::call_once_storage<T> *>(storage_map.at (k));
156+ result = last_storage_ = reinterpret_cast <T *>(v->storage );
162157 });
163158 }
164159 assert (result != nullptr );
165160 return *result;
166161 }
167162
168163 constexpr gil_safe_call_once_and_store () = default;
169- PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store () {
170- if (is_initialized_by_atleast_one_interpreter_) {
171- detail::with_internals ([&](detail::internals &internals) {
172- const void *key = reinterpret_cast <const void *>(this );
173- auto &storage_map = internals.call_once_storage_map ;
174- auto it = storage_map.find (key);
175- if (it != storage_map.end ()) {
176- delete it->second ;
177- storage_map.erase (it);
178- }
179- });
180- }
181- }
164+ // The instance is a global static, so its destructor runs when the process
165+ // is terminating. Therefore, do nothing here because the Python interpreter
166+ // may have been finalized already.
167+ PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store () = default ;
182168
183169private:
184170 // No storage needed when subinterpreter support is enabled.
0 commit comments