From 572f4a47d45806fd58e4b173e0898584b421490e 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_GetUnsafe() function Add PyThreadState_GetUnsafe() 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 60f5c81cff572c7..022d6e2aad7cf76 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_GetUnsafe() + + 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, 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 de23172ac7a43b1..eed7d402ee5bf03 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -924,6 +924,13 @@ New Features references) now supports the :ref:`Limited API `. (Contributed by Victor Stinner in :gh:`108634`.) +* Add :c:func:`PyThreadState_GetUnsafe()` 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 e5987191cfe08c4..c0fc873c584a40c 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_GetUnsafe(); \ if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \ break; \ } \ diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index fc5f58db86dbe87..2b0a98a3e3b90ff 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -210,7 +210,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_GetUnsafe(void); // Disable tracing and profiling. PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate); diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index a30036aeb57e05f..bb3101b5dcbf839 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -77,7 +77,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_GetUnsafe(). */ static inline PyThreadState* _PyThreadState_GET(void) { diff --git a/Include/pystate.h b/Include/pystate.h index e6b4de979c87b88..8c1c061df0a84bc 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_GetUnsafe() 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 000000000000000..e68b65a5e067ad2 --- /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_GetUnsafe()` 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 ab33702cdfd8724..d5a1683ca59fe4d 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2445,8 +2445,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_GetUnsafe() + PyThreadState *tstate3 = PyThreadState_GetUnsafe(); assert(tstate3 == tstate); // PyThreadState_EnterTracing(), PyThreadState_LeaveTracing() diff --git a/Modules/getpath.c b/Modules/getpath.c index 3b926cac0d3f24e..6f76a84e78bf625 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 46ea2c4f678db8a..d36f1f68ff305df 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1828,7 +1828,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) //--------------------------------- PyThreadState * -_PyThreadState_UncheckedGet(void) +PyThreadState_GetUnsafe(void) { return current_fast_get(&_PyRuntime); }