From 826b4c5477be035be68b561ec968a0df86bd357a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 22 Nov 2019 13:55:29 +0100 Subject: [PATCH 1/3] bpo-38500: Add PyInterpreterState_SetEvalFrameFunc() Add a public API to get and set the frame evaluation function: * Rename the internal _PyFrameEvalFunction type to PyFrameEvalFunction and make it public * Add PyInterpreterState_GetEvalFrameFunc() and PyInterpreterState_SetEvalFrameFunc() functions --- Doc/c-api/init.rst | 25 +++++++++++++++++++ Include/cpython/pystate.h | 10 ++++++++ Include/internal/pycore_pystate.h | 4 +-- .../2019-11-22-14-06-28.bpo-38500.nPEdjH.rst | 3 +++ Python/pystate.c | 14 +++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 86bf7f9eec65e7..06ddc67165aca4 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1083,6 +1083,31 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.8 +.. c:type:: PyObject* (*PyFrameEvalFunction)(PyFrameObject *frame, int throwflag) + + Type of a frame evaluation function. + + The *throwflag* parameter is used by the ``throw()`` method of generators: + if non-zero, handle the current exception. + + .. versionadded:: 3.8.1 + +.. c:function:: PyFrameEvalFunction PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) + + Get the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.8.1 + +.. c:function:: void PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, PyFrameEvalFunction eval_frame); + + Set the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.8.1 + .. c:function:: PyObject* PyThreadState_GetDict() diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index d1792575c97378..e4f0bb064d4607 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -186,6 +186,16 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); +/* Frame evaluation API */ + +typedef PyObject* (*PyFrameEvalFunction)(struct _frame *, int); + +PyAPI_FUNC(PyFrameEvalFunction) PyInterpreterState_GetEvalFrameFunc( + PyInterpreterState *interp); +PyAPI_FUNC(void) PyInterpreterState_SetEvalFrameFunc( + PyInterpreterState *interp, + PyFrameEvalFunction eval_frame); + /* cross-interpreter data */ struct _xid; diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index aa2103f07c795b..3c21f58c9ccf65 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -54,8 +54,6 @@ struct _ceval_runtime_state { /* interpreter state */ -typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int); - // The PyInterpreterState typedef is in Include/pystate.h. struct _is { @@ -113,7 +111,7 @@ struct _is { PyObject *builtins_copy; PyObject *import_func; /* Initialized to PyEval_EvalFrameDefault(). */ - _PyFrameEvalFunction eval_frame; + PyFrameEvalFunction eval_frame; Py_ssize_t co_extra_user_count; freefunc co_extra_freefuncs[MAX_CO_EXTRA_USERS]; diff --git a/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst new file mode 100644 index 00000000000000..3cca07aaba00bb --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst @@ -0,0 +1,3 @@ +Add a public API to get and set the frame evaluation function: add +:c:func:`PyInterpreterState_GetEvalFrameFunc` and +:c:func:`PyInterpreterState_SetEvalFrameFunc` C functions diff --git a/Python/pystate.c b/Python/pystate.c index d792380de46498..067de50151a49f 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1721,6 +1721,20 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) } +PyFrameEvalFunction +PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) +{ + return interp->eval_frame; +} + + +void +PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, + PyFrameEvalFunction eval_frame) +{ + interp->eval_frame = eval_frame; +} + #ifdef __cplusplus } #endif From 5531a53e84b18c4949b6cf0ce27ecb7473beba35 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 16 Nov 2019 00:47:25 +0100 Subject: [PATCH 2/3] bpo-38818: PyInterpreterState.eval_frame now pass tstate PyInterpreterState.eval_frame (PEP 523) now requires a new mandatory tstate parameter (PyThreadState*). --- Doc/c-api/init.rst | 2 +- Doc/whatsnew/3.9.rst | 4 ++++ Include/cpython/ceval.h | 5 ++++- Include/cpython/pystate.h | 2 +- Include/internal/pycore_ceval.h | 2 +- .../next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst | 2 ++ Python/ceval.c | 3 +-- 7 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 06ddc67165aca4..50a94cd0b5bbd5 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1083,7 +1083,7 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.8 -.. c:type:: PyObject* (*PyFrameEvalFunction)(PyFrameObject *frame, int throwflag) +.. c:type:: PyObject* (*PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag) Type of a frame evaluation function. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index a3ad98d020642e..3c49082c11f312 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -239,6 +239,10 @@ Build and C API Changes removed in Python 3.3. (Contributed by Victor Stinner in :issue:`38896`.) +* ``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory + *tstate* parameter (``PyThreadState*``). + (Contributed by Victor Stinner in :issue:`38818`.) + Deprecated ========== diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index e601304589f762..0a88d479a317cf 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -21,7 +21,10 @@ PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *); flag was set, else return 0. */ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); -PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(struct _frame *f, int exc); +PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault( + PyThreadState *tstate, + struct _frame *f, + int exc); PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index e4f0bb064d4607..569e715b6c2f0b 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -188,7 +188,7 @@ typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); /* Frame evaluation API */ -typedef PyObject* (*PyFrameEvalFunction)(struct _frame *, int); +typedef PyObject* (*PyFrameEvalFunction)(PyThreadState *tstate, struct _frame *, int); PyAPI_FUNC(PyFrameEvalFunction) PyInterpreterState_GetEvalFrameFunc( PyInterpreterState *interp); diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 857fc0b2524fe8..26abb61aad0053 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -40,7 +40,7 @@ void _PyEval_Fini(void); static inline PyObject* _PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag) { - return tstate->interp->eval_frame(f, throwflag); + return tstate->interp->eval_frame(tstate, f, throwflag); } extern PyObject *_PyEval_EvalCode( diff --git a/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst b/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst new file mode 100644 index 00000000000000..a5b1ef47f8b61f --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-16-01-12-32.bpo-38818.bUyp8O.rst @@ -0,0 +1,2 @@ +``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory +*tstate* parameter (``PyThreadState*``). diff --git a/Python/ceval.c b/Python/ceval.c index 96ed329b0d9952..237dbd4681e144 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -743,7 +743,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } PyObject* _Py_HOT_FUNCTION -_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) +_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) { #ifdef DXPAIRS int lastopcode = 0; @@ -755,7 +755,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) PyObject **fastlocals, **freevars; PyObject *retval = NULL; /* Return value */ _PyRuntimeState * const runtime = &_PyRuntime; - PyThreadState * const tstate = _PyRuntimeState_GetThreadState(runtime); struct _ceval_runtime_state * const ceval = &runtime->ceval; _Py_atomic_int * const eval_breaker = &ceval->eval_breaker; PyCodeObject *co; From e1b00f5d2bc72f187fe6b1f6c49cbea568de34dc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 22 Nov 2019 22:41:00 +0100 Subject: [PATCH 3/3] Document tstate addition --- Doc/c-api/init.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 50a94cd0b5bbd5..f7297999c08204 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1092,6 +1092,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.8.1 + .. versionchanged:: 3.8.1 + Add *tstate* parameter. + + .. c:function:: PyFrameEvalFunction PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) Get the frame evaluation function.