Skip to content

Commit

Permalink
pythongh-108867: Add PyThreadState_GetUnsafe() function
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
vstinner committed Sep 6, 2023
1 parent 6f8411c commit 572f4a4
Show file tree
Hide file tree
Showing 10 changed files with 32 additions and 8 deletions.
11 changes: 11 additions & 0 deletions Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,13 @@ New Features
references) now supports the :ref:`Limited API <limited-c-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
----------------------

Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/object.h
Original file line number Diff line number Diff line change
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_GetUnsafe(); \
if (_PyTrash_begin(_tstate, _PyObject_CAST(op))) { \
break; \
} \
Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
2 changes: 1 addition & 1 deletion Include/pystate.h
Original file line number Diff line number Diff line change
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_GetUnsafe() and _PyThreadState_GET(). */
PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void);

// Alias to PyThreadState_Get()
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion Modules/getpath.c
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -1828,7 +1828,7 @@ PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
//---------------------------------

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

0 comments on commit 572f4a4

Please sign in to comment.