@@ -1168,17 +1168,6 @@ inline void add_class_method(object& cls, const char *name_, const cpp_function
11681168 }
11691169}
11701170
1171- // Thread state manipulation C API should not be called while Python runtime is finalizing.
1172- // For more detail see https://docs.python.org/3.7/c-api/init.html#c.PyEval_RestoreThread
1173- // `is_finalizing()` provides a version agnostic way to check if runtime is finalizing.
1174- inline bool is_finalizing () {
1175- #if PY_VERSION_HEX >= 0x03070000
1176- return _Py_IsFinalizing ();
1177- #else
1178- return false ;
1179- #endif
1180- }
1181-
11821171PYBIND11_NAMESPACE_END (detail)
11831172
11841173// / Given a pointer to a member function, cast it to its `Derived` version.
@@ -2132,13 +2121,21 @@ class gil_scoped_acquire {
21322121 pybind11_fail (" scoped_acquire::dec_ref(): internal error!" );
21332122 #endif
21342123 PyThreadState_Clear (tstate);
2135- if (! detail::is_finalizing () )
2124+ if (active )
21362125 PyThreadState_DeleteCurrent ();
21372126 PYBIND11_TLS_DELETE_VALUE (detail::get_internals ().tstate );
21382127 release = false ;
21392128 }
21402129 }
21412130
2131+ // / This method will disable the PyThreadState_DeleteCurrent call. This
2132+ // / should be called if the interpreter is shutting down, as the thread
2133+ // / deletion is not allowed during shutdown.
2134+ // / (_Py_IsFinalizing() on Python 3.7+)
2135+ PYBIND11_NOINLINE void disarm () {
2136+ active = false ;
2137+ }
2138+
21422139 PYBIND11_NOINLINE ~gil_scoped_acquire () {
21432140 dec_ref ();
21442141 if (release)
@@ -2147,6 +2144,7 @@ class gil_scoped_acquire {
21472144private:
21482145 PyThreadState *tstate = nullptr ;
21492146 bool release = true ;
2147+ bool active = true ;
21502148};
21512149
21522150class gil_scoped_release {
@@ -2162,11 +2160,20 @@ class gil_scoped_release {
21622160 PYBIND11_TLS_DELETE_VALUE (key);
21632161 }
21642162 }
2163+ //
2164+ // / This method will disable the PyThreadState_DeleteCurrent call. This
2165+ // / should be called if the interpreter is shutting down, as the thread
2166+ // / deletion is not allowed during shutdown.
2167+ // / (_Py_IsFinalizing() on Python 3.7+)
2168+ PYBIND11_NOINLINE void disarm () {
2169+ active = false ;
2170+ }
2171+
21652172 ~gil_scoped_release () {
21662173 if (!tstate)
21672174 return ;
21682175 // `PyEval_RestoreThread()` should not be called if runtime is finalizing
2169- if (! detail::is_finalizing () )
2176+ if (active )
21702177 PyEval_RestoreThread (tstate);
21712178 if (disassoc) {
21722179 auto key = detail::get_internals ().tstate ;
@@ -2176,24 +2183,31 @@ class gil_scoped_release {
21762183private:
21772184 PyThreadState *tstate;
21782185 bool disassoc;
2186+ bool active = true ;
21792187};
21802188#elif defined(PYPY_VERSION)
21812189class gil_scoped_acquire {
21822190 PyGILState_STATE state;
21832191public:
21842192 gil_scoped_acquire () { state = PyGILState_Ensure (); }
21852193 ~gil_scoped_acquire () { PyGILState_Release (state); }
2194+ void disarm () {}
21862195};
21872196
21882197class gil_scoped_release {
21892198 PyThreadState *state;
21902199public:
21912200 gil_scoped_release () { state = PyEval_SaveThread (); }
21922201 ~gil_scoped_release () { PyEval_RestoreThread (state); }
2202+ void disarm () {}
21932203};
21942204#else
2195- class gil_scoped_acquire { };
2196- class gil_scoped_release { };
2205+ class gil_scoped_acquire {
2206+ void disarm () {}
2207+ };
2208+ class gil_scoped_release {
2209+ void disarm () {}
2210+ };
21972211#endif
21982212
21992213error_already_set::~error_already_set () {
0 commit comments