*tstate*, which should not be *NULL*. The lock must have been created earlier.
If this thread already has the lock, deadlock ensues.
+ .. note::
+ Calling this function from a thread when the runtime is finalizing
+ will terminate the thread, even if the thread was not created by Python.
+ You can use :c:func:`_Py_IsFinalizing` or :func:`sys.is_finalizing` to
+ check if the interpreter is in process of being finalized before calling
+ this function to avoid unwanted termination.
+
+ .. versionchanged:: 3.8
+ Updated to be consistent with :c:func:`PyEval_RestoreThread`,
+ :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`,
+ and terminate the current thread if called while the interpreter is finalizing.
+
:c:func:`PyEval_RestoreThread` is a higher-level function which is always
available (even when threads have not been initialized).
:c:func:`PyEval_RestoreThread` or :c:func:`PyEval_AcquireThread`
instead.
+ .. note::
+ Calling this function from a thread when the runtime is finalizing
+ will terminate the thread, even if the thread was not created by Python.
+ You can use :c:func:`_Py_IsFinalizing` or :func:`sys.is_finalizing` to
+ check if the interpreter is in process of being finalized before calling
+ this function to avoid unwanted termination.
+
+ .. versionchanged:: 3.8
+ Updated to be consistent with :c:func:`PyEval_RestoreThread`,
+ :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`,
+ and terminate the current thread if called while the interpreter is finalizing.
+
.. c:function:: void PyEval_ReleaseLock()
always use the ``sys.platform.startswith('aix')``.
(Contributed by M. Felt in :issue:`36588`.)
+* :c:func:`PyEval_AcquireLock` and :c:func:`PyEval_AcquireThread` now
+ terminate the current thread if called while the interpreter is
+ finalizing, making them consistent with :c:func:`PyEval_RestoreThread`,
+ :c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`. If this
+ behaviour is not desired, guard the call by checking :c:func:`_Py_IsFinalizing`
+ or :c:func:`sys.is_finalizing`.
+
Changes in the Python API
-------------------------
--- /dev/null
+:c:func:`PyEval_AcquireLock` and :c:func:`PyEval_AcquireThread` now
+terminate the current thread if called while the interpreter is
+finalizing, making them consistent with :c:func:`PyEval_RestoreThread`,
+:c:func:`Py_END_ALLOW_THREADS`, and :c:func:`PyGILState_Ensure`.
\ No newline at end of file
static int check_args_iterable(PyObject *func, PyObject *vararg);
static void format_kwargs_error(PyObject *func, PyObject *kwargs);
static void format_awaitable_error(PyTypeObject *, int);
+static inline void exit_thread_if_finalizing(PyThreadState *);
#define NAME_ERROR_MSG \
"name '%.200s' is not defined"
}
}
+static inline void
+exit_thread_if_finalizing(PyThreadState *tstate)
+{
+ /* _Py_Finalizing is protected by the GIL */
+ if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
+ drop_gil(tstate);
+ PyThread_exit_thread();
+ Py_UNREACHABLE();
+ }
+}
+
void
PyEval_AcquireLock(void)
{
if (tstate == NULL)
Py_FatalError("PyEval_AcquireLock: current thread state is NULL");
take_gil(tstate);
+ exit_thread_if_finalizing(tstate);
}
void
/* Check someone has called PyEval_InitThreads() to create the lock */
assert(gil_created());
take_gil(tstate);
+ exit_thread_if_finalizing(tstate);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError(
"PyEval_AcquireThread: non-NULL old thread state");
int err = errno;
take_gil(tstate);
- /* _Py_Finalizing is protected by the GIL */
- if (_Py_IsFinalizing() && !_Py_CURRENTLY_FINALIZING(tstate)) {
- drop_gil(tstate);
- PyThread_exit_thread();
- Py_UNREACHABLE();
- }
+ exit_thread_if_finalizing(tstate);
errno = err;
PyThreadState_Swap(tstate);
take_gil(tstate);
/* Check if we should make a quick exit. */
- if (_Py_IsFinalizing() &&
- !_Py_CURRENTLY_FINALIZING(tstate))
- {
- drop_gil(tstate);
- PyThread_exit_thread();
- }
+ exit_thread_if_finalizing(tstate);
if (PyThreadState_Swap(tstate) != NULL)
Py_FatalError("ceval: orphan tstate");