From 23720918e96122c980f3d1a0a1663b04c3a8aad7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 Sep 2023 11:33:16 +0200 Subject: [PATCH] gh-108867: Add PyThreadState_GetUnchecked() function Add PyThreadState_GetUnchecked() function: similar to PyThreadState_Get(), but don't issue a fatal error if it is NULL. The caller is responsible to check if the result is NULL. Previously, this function was private and known as _PyThreadState_UncheckedGet(). --- Doc/c-api/init.rst | 11 +++++++++++ Doc/whatsnew/3.13.rst | 7 +++++++ Include/cpython/object.h | 2 +- Include/cpython/pystate.h | 2 +- Include/internal/pycore_pystate.h | 2 +- Include/pystate.h | 2 +- .../2023-09-04-11-47-12.gh-issue-108867.Cr_LKd.rst | 5 +++++ Modules/_testcapimodule.c | 4 ++-- Modules/getpath.c | 3 ++- Python/pystate.c | 2 +- 10 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-09-04-11-47-12.gh-issue-108867.Cr_LKd.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 60f5c81cff572c..336150f22420bc 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -871,6 +871,17 @@ code, or when embedding the Python interpreter: the caller needn't check for ``NULL``). +.. c:function:: PyThreadState* PyThreadState_GetUnchecked() + + Similar to :c:func:`PyThreadState_Get`, but don't kill the process with a + fatal error if it is NULL. The caller is responsible to check if the result + is NULL. + + .. versionadded:: 3.13 + In Python 3.5 to 3.12, the function was private and known as + ``_PyThreadState_UncheckedGet()``. + + .. c:function:: PyThreadState* PyThreadState_Swap(PyThreadState *tstate) Swap the current thread state with the thread state given by the argument diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index a99d1141f53d77..785deea1c1e48f 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1003,6 +1003,13 @@ New Features functions on Python 3.11 and 3.12. (Contributed by Victor Stinner in :gh:`107073`.) +* Add :c:func:`PyThreadState_GetUnchecked()` function: similar to + :c:func:`PyThreadState_Get()`, but don't kill the process with a fatal error + if it is NULL. The caller is responsible to check if the result is NULL. + Previously, the function was private and known as + ``_PyThreadState_UncheckedGet()``. + (Contributed by Victor Stinner in :gh:`108867`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 3838f19c75a230..ede394d9673d7e 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -425,7 +425,7 @@ PyAPI_FUNC(int) _PyTrash_cond(PyObject *op, destructor dealloc); /* If "cond" is false, then _tstate remains NULL and the deallocator \ * is run normally without involving the trashcan */ \ if (cond) { \ - _tstate = _PyThreadState_UncheckedGet(); \ + _tstate = PyThreadState_GetUnchecked(); \ if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \ break; \ } \ diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index af5cc4a2f3bf63..8fd06242bc82e0 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -218,7 +218,7 @@ struct _ts { /* Similar to PyThreadState_Get(), but don't issue a fatal error * if it is NULL. */ -PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void); +PyAPI_FUNC(PyThreadState *) PyThreadState_GetUnchecked(void); // Disable tracing and profiling. diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 5f8b576e4a69ab..a60d949bff1eba 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -93,7 +93,7 @@ PyAPI_FUNC(PyThreadState *) _PyThreadState_GetCurrent(void); The caller must hold the GIL. - See also PyThreadState_Get() and _PyThreadState_UncheckedGet(). */ + See also PyThreadState_Get() and PyThreadState_GetUnchecked(). */ static inline PyThreadState* _PyThreadState_GET(void) { diff --git a/Include/pystate.h b/Include/pystate.h index e6b4de979c87b8..727b8fbfffe0e6 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -56,7 +56,7 @@ PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); The caller must hold the GIL. - See also _PyThreadState_UncheckedGet() and _PyThreadState_GET(). */ + See also PyThreadState_GetUnchecked() and _PyThreadState_GET(). */ PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); // Alias to PyThreadState_Get() diff --git a/Misc/NEWS.d/next/C API/2023-09-04-11-47-12.gh-issue-108867.Cr_LKd.rst b/Misc/NEWS.d/next/C API/2023-09-04-11-47-12.gh-issue-108867.Cr_LKd.rst new file mode 100644 index 00000000000000..2f56466833f6dd --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-09-04-11-47-12.gh-issue-108867.Cr_LKd.rst @@ -0,0 +1,5 @@ +Add :c:func:`PyThreadState_GetUnchecked()` function: similar to +:c:func:`PyThreadState_Get()`, but don't kill the process with a fatal error if +it is NULL. The caller is responsible to check if the result is NULL. +Previously, the function was private and known as +``_PyThreadState_UncheckedGet()``. Patch by Victor Stinner. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 64bcb49d365774..a46d986c18ecd4 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2458,8 +2458,8 @@ test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args)) PyThreadState *tstate2 = PyThreadState_Get(); assert(tstate2 == tstate); - // private _PyThreadState_UncheckedGet() - PyThreadState *tstate3 = _PyThreadState_UncheckedGet(); + // PyThreadState_GetUnchecked() + PyThreadState *tstate3 = PyThreadState_GetUnchecked(); assert(tstate3 == tstate); // PyThreadState_EnterTracing(), PyThreadState_LeaveTracing() diff --git a/Modules/getpath.c b/Modules/getpath.c index 3b926cac0d3f24..6f76a84e78bf62 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -6,6 +6,7 @@ #include "pycore_pathconfig.h" // _PyPathConfig_ReadGlobal() #include "pycore_pyerrors.h" // _PyErr_WriteUnraisableMsg() #include "pycore_pymem.h" // _PyMem_RawWcsdup() +#include "pycore_pystate.h" // _PyThreadState_GET() #include "marshal.h" // PyMarshal_ReadObjectFromString #include "osdefs.h" // DELIM @@ -821,7 +822,7 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config) return status; } - if (!_PyThreadState_UncheckedGet()) { + if (!_PyThreadState_GET()) { return PyStatus_Error("cannot calculate path configuration without GIL"); } diff --git a/Python/pystate.c b/Python/pystate.c index 25a957c31f0134..ae33259f8df2f6 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1908,7 +1908,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) //--------------------------------- PyThreadState * -_PyThreadState_UncheckedGet(void) +PyThreadState_GetUnchecked(void) { return current_fast_get(&_PyRuntime); }