Skip to content

Commit

Permalink
gh-108867: Add PyThreadState_GetUnchecked() function (#108870)
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
vstinner committed Oct 3, 2023
1 parent 6ab6040 commit d735016
Show file tree
Hide file tree
Showing 10 changed files with 34 additions and 8 deletions.
13 changes: 13 additions & 0 deletions Doc/c-api/init.rst
Expand Up @@ -870,6 +870,19 @@ code, or when embedding the Python interpreter:
When the current thread state is ``NULL``, this issues a fatal error (so that
the caller needn't check for ``NULL``).
See also :c:func:`PyThreadState_GetUnchecked`.
.. 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)
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.13.rst
Expand Up @@ -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
----------------------

Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/object.h
Expand Up @@ -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; \
} \
Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/pystate.h
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pystate.h
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion Include/pystate.h
Expand Up @@ -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()
Expand Down
@@ -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.
4 changes: 2 additions & 2 deletions Modules/_testcapimodule.c
Expand Up @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion Modules/getpath.c
Expand Up @@ -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
Expand Down Expand Up @@ -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");
}

Expand Down
2 changes: 1 addition & 1 deletion Python/pystate.c
Expand Up @@ -1908,7 +1908,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
//---------------------------------

PyThreadState *
_PyThreadState_UncheckedGet(void)
PyThreadState_GetUnchecked(void)
{
return current_fast_get(&_PyRuntime);
}
Expand Down

0 comments on commit d735016

Please sign in to comment.