.. versionadded:: 3.9
+.. c:function:: void PyThreadState_EnterTracing(PyThreadState *tstate)
+
+ Suspend tracing and profiling in the Python thread state *tstate*.
+
+ Resume them using the:c:func:`PyThreadState_LeaveTracing` function.
+
+ .. versionadded:: 3.11
+
+
+.. c:function:: void PyThreadState_LeaveTracing(PyThreadState *tstate)
+
+ Resume tracing and profiling in the Python thread state *tstate* suspended
+ by the:c:func:`PyThreadState_EnterTracing` function.
+
+ See also :c:func:`PyEval_SetTrace` and :c:func:`PyEval_SetProfile`
+ functions.
+
+ .. versionadded:: 3.11
+
+
.. c:function:: PyInterpreterState* PyInterpreterState_Get(void)
Get the current interpreter.
profile function is called for all monitored events except :const:`PyTrace_LINE`
:const:`PyTrace_OPCODE` and :const:`PyTrace_EXCEPTION`.
+ See also the :func:`sys.setprofile` function.
+
The caller must hold the :term:`GIL`.
will not receive :const:`PyTrace_C_CALL`, :const:`PyTrace_C_EXCEPTION` or
:const:`PyTrace_C_RETURN` as a value for the *what* parameter.
+ See also the :func:`sys.settrace` function.
+
The caller must hold the :term:`GIL`.
* Add a new :c:func:`PyType_GetQualName` function to get type's qualified name.
(Contributed by Hai Shi in :issue:`42035`.)
+* Add new :c:func:`PyThreadState_EnterTracing` and
+ :c:func:`PyThreadState_LeaveTracing` functions to the limited C API to
+ suspend and resume tracing and profiling.
+ (Contributed by Victor Stinner in :issue:`43760`.)
+
Porting to Python 3.11
----------------------
PyAPI_FUNC(PyObject *) _PyThreadState_GetDict(PyThreadState *tstate);
+// Disable tracing and profiling.
+PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate);
+
+// Reset tracing and profiling: enable them if a trace function or a profile
+// function is set, otherwise disable them.
+PyAPI_FUNC(void) PyThreadState_LeaveTracing(PyThreadState *tstate);
+
/* PyGILState */
/* Helper/diagnostic function - return 1 if the current thread
}
-/* Other */
+// PyThreadState functions
PyAPI_FUNC(void) _PyThreadState_Init(
PyThreadState *tstate);
_PyRuntimeState *runtime,
PyThreadState *tstate);
+static inline void
+_PyThreadState_DisableTracing(PyThreadState *tstate)
+{
+ tstate->cframe->use_tracing = 0;
+}
+
+static inline void
+_PyThreadState_ResetTracing(PyThreadState *tstate)
+{
+ int use_tracing = (tstate->c_tracefunc != NULL
+ || tstate->c_profilefunc != NULL);
+ tstate->cframe->use_tracing = (use_tracing ? 255 : 0);
+}
+
+
+/* Other */
+
PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
struct _gilstate_runtime_state *gilstate,
PyThreadState *newts);
--- /dev/null
+Add new :c:func:`PyThreadState_EnterTracing`, and
+:c:func:`PyThreadState_LeaveTracing` functions to the limited C API to suspend
+and resume tracing and profiling.
+Patch by Victor Stinner.
#define PY_SSIZE_T_CLEAN
#include "Python.h"
-#include "datetime.h"
-#include "marshal.h"
+#include "frameobject.h" // PyFrame_Check()
+#include "datetime.h" // PyDateTimeAPI
+#include "marshal.h" // PyMarshal_WriteLongToFile
#include "structmember.h" // PyMemberDef
-#include <float.h>
+#include <float.h> // FLT_MAX
#include <signal.h>
#ifdef MS_WINDOWS
-# include <winsock2.h> /* struct timeval */
+# include <winsock2.h> // struct timeval
#endif
#ifdef HAVE_SYS_WAIT_H
-#include <sys/wait.h> /* For W_STOPCODE */
+#include <sys/wait.h> // W_STOPCODE
#endif
#ifdef Py_BUILD_CORE
# error "_testcapi must test the public Python C API, not CPython internal C API"
#endif
+
+// Forward declarations
static struct PyModuleDef _testcapimodule;
static PyType_Spec HeapTypeNameType_Spec;
-
static PyObject *TestError; /* set to exception object in init */
+
/* Raise TestError with test_name + ": " + msg, and return NULL. */
static PyObject *
}
+// Test PyThreadState C API
+static PyObject *
+test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ // PyThreadState_Get()
+ PyThreadState *tstate = PyThreadState_Get();
+ assert(tstate != NULL);
+
+ // PyThreadState_GET()
+ PyThreadState *tstate2 = PyThreadState_Get();
+ assert(tstate2 == tstate);
+
+ // private _PyThreadState_UncheckedGet()
+ PyThreadState *tstate3 = _PyThreadState_UncheckedGet();
+ assert(tstate3 == tstate);
+
+ // PyThreadState_EnterTracing(), PyThreadState_LeaveTracing()
+ PyThreadState_EnterTracing(tstate);
+ PyThreadState_LeaveTracing(tstate);
+
+ // PyThreadState_GetDict(): no tstate argument
+ PyObject *dict = PyThreadState_GetDict();
+ // PyThreadState_GetDict() API can return NULL if PyDict_New() fails,
+ // but it should not occur in practice.
+ assert(dict != NULL);
+ assert(PyDict_Check(dict));
+ // dict is a borrowed reference
+
+ // private _PyThreadState_GetDict()
+ PyObject *dict2 = _PyThreadState_GetDict(tstate);
+ assert(dict2 == dict);
+ // dict2 is a borrowed reference
+
+ // PyThreadState_GetInterpreter()
+ PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
+ assert(interp != NULL);
+
+ // PyThreadState_GetFrame()
+ PyFrameObject*frame = PyThreadState_GetFrame(tstate);
+ assert(frame != NULL);
+ assert(PyFrame_Check(frame));
+ Py_DECREF(frame);
+
+ // PyThreadState_GetID()
+ uint64_t id = PyThreadState_GetID(tstate);
+ assert(id >= 1);
+
+ Py_RETURN_NONE;
+}
+
+
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
static PyObject *getargs_s_hash_int(PyObject *, PyObject *, PyObject*);
{"fatal_error", test_fatal_error, METH_VARARGS,
PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")},
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
+ {"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};
if (tstate->tracing)
return 0;
tstate->tracing++;
- tstate->cframe->use_tracing = 0;
+ _PyThreadState_DisableTracing(tstate);
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
if (f == NULL) {
return -1;
}
result = func(obj, f, what, arg);
f->f_lineno = 0;
- tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL)
- || (tstate->c_profilefunc != NULL)) ? 255 : 0;
+ _PyThreadState_ResetTracing(tstate);
tstate->tracing--;
return result;
}
PyObject *result;
tstate->tracing = 0;
- tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL)
- || (tstate->c_profilefunc != NULL)) ? 255 : 0;
+ _PyThreadState_ResetTracing(tstate);
result = PyObject_Call(func, args, NULL);
tstate->tracing = save_tracing;
tstate->cframe->use_tracing = save_use_tracing;
tstate->c_profilefunc = NULL;
tstate->c_profileobj = NULL;
/* Must make sure that tracing is not ignored if 'profileobj' is freed */
- tstate->cframe->use_tracing = tstate->c_tracefunc != NULL;
+ _PyThreadState_ResetTracing(tstate);
Py_XDECREF(profileobj);
Py_XINCREF(arg);
tstate->c_profilefunc = func;
/* Flag that tracing or profiling is turned on */
- tstate->cframe->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL) ? 255 : 0;
+ _PyThreadState_ResetTracing(tstate);
return 0;
}
tstate->c_tracefunc = NULL;
tstate->c_traceobj = NULL;
/* Must make sure that profiling is not ignored if 'traceobj' is freed */
- tstate->cframe->use_tracing = (tstate->c_profilefunc != NULL) ? 255 : 0;
+ _PyThreadState_ResetTracing(tstate);
Py_XDECREF(traceobj);
Py_XINCREF(arg);
tstate->c_tracefunc = func;
/* Flag that tracing or profiling is turned on */
- tstate->cframe->use_tracing = ((func != NULL)
- || (tstate->c_profilefunc != NULL)) ? 255 : 0;
+ _PyThreadState_ResetTracing(tstate);
return 0;
}
}
+void
+PyThreadState_EnterTracing(PyThreadState *tstate)
+{
+ tstate->tracing++;
+ _PyThreadState_DisableTracing(tstate);
+}
+
+void
+PyThreadState_LeaveTracing(PyThreadState *tstate)
+{
+ tstate->tracing--;
+ _PyThreadState_ResetTracing(tstate);
+}
+
+
+
/* Routines for advanced debuggers, requested by David Beazley.
Don't use unless you know what you are doing! */
}
/* Disallow tracing in hooks unless explicitly enabled */
- ts->tracing++;
- ts->cframe->use_tracing = 0;
+ PyThreadState_EnterTracing(ts);
while ((hook = PyIter_Next(hooks)) != NULL) {
_Py_IDENTIFIER(__cantrace__);
PyObject *o;
break;
}
if (canTrace) {
- ts->cframe->use_tracing = (ts->c_tracefunc || ts->c_profilefunc) ? 255 : 0;
- ts->tracing--;
+ PyThreadState_LeaveTracing(ts);
}
PyObject* args[2] = {eventName, eventArgs};
o = _PyObject_FastCallTstate(ts, hook, args, 2);
if (canTrace) {
- ts->tracing++;
- ts->cframe->use_tracing = 0;
+ PyThreadState_EnterTracing(ts);
}
if (!o) {
break;
Py_DECREF(o);
Py_CLEAR(hook);
}
- ts->cframe->use_tracing = (ts->c_tracefunc || ts->c_profilefunc) ? 255 : 0;
- ts->tracing--;
+ PyThreadState_LeaveTracing(ts);
if (_PyErr_Occurred(ts)) {
goto exit;
}