Skip to content

Commit bb8cee6

Browse files
committed
feat: disarm
1 parent e5fe8d3 commit bb8cee6

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

include/pybind11/pybind11.h

+29-15
Original file line numberDiff line numberDiff line change
@@ -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-
11821171
PYBIND11_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 {
21472144
private:
21482145
PyThreadState *tstate = nullptr;
21492146
bool release = true;
2147+
bool active = true;
21502148
};
21512149

21522150
class 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 {
21762183
private:
21772184
PyThreadState *tstate;
21782185
bool disassoc;
2186+
bool active = true;
21792187
};
21802188
#elif defined(PYPY_VERSION)
21812189
class gil_scoped_acquire {
21822190
PyGILState_STATE state;
21832191
public:
21842192
gil_scoped_acquire() { state = PyGILState_Ensure(); }
21852193
~gil_scoped_acquire() { PyGILState_Release(state); }
2194+
void disarm() {}
21862195
};
21872196

21882197
class gil_scoped_release {
21892198
PyThreadState *state;
21902199
public:
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

21992213
error_already_set::~error_already_set() {

0 commit comments

Comments
 (0)