summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorPablo Galindo Salgado <Pablogsal@gmail.com>2022-08-24 22:21:39 (GMT)
committerGitHub <noreply@github.com>2022-08-24 22:21:39 (GMT)
commite34c82abeb7ace09e6b5d116585c47cc372996c1 (patch)
tree16f130870af42de041ddf52a36540b9c421aec8c /Python
parent657976ad950e56b33b7dc15e64a0baecdd184f5a (diff)
downloadcpython-e34c82abeb7ace09e6b5d116585c47cc372996c1.zip
cpython-e34c82abeb7ace09e6b5d116585c47cc372996c1.tar.gz
cpython-e34c82abeb7ace09e6b5d116585c47cc372996c1.tar.bz2
GH-93503: Add thread-specific APIs to set profiling and tracing functions in the C-API (#93504)
* gh-93503: Add APIs to set profiling and tracing functions in all threads in the C-API * Use a separate API * Fix NEWS entry * Add locks around the loop * Document ignoring exceptions * Use the new APIs in the sys module * Update docs
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c45
-rw-r--r--Python/clinic/sysmodule.c.h26
-rw-r--r--Python/sysmodule.c61
3 files changed, 131 insertions, 1 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 1ab104c..ac77ab8 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -96,6 +96,10 @@
#define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL)
#endif
+#define HEAD_LOCK(runtime) \
+ PyThread_acquire_lock((runtime)->interpreters.mutex, WAIT_LOCK)
+#define HEAD_UNLOCK(runtime) \
+ PyThread_release_lock((runtime)->interpreters.mutex)
/* Forward declarations */
static PyObject *trace_call_function(
@@ -6455,6 +6459,27 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
}
}
+void
+PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *this_tstate = _PyThreadState_GET();
+ PyInterpreterState* interp = this_tstate->interp;
+
+ _PyRuntimeState *runtime = &_PyRuntime;
+ HEAD_LOCK(runtime);
+ PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
+ HEAD_UNLOCK(runtime);
+
+ while (ts) {
+ if (_PyEval_SetProfile(ts, func, arg) < 0) {
+ _PyErr_WriteUnraisableMsg("in PyEval_SetProfileAllThreads", NULL);
+ }
+ HEAD_LOCK(runtime);
+ ts = PyThreadState_Next(ts);
+ HEAD_UNLOCK(runtime);
+ }
+}
+
int
_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
{
@@ -6508,6 +6533,26 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
}
}
+void
+PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *this_tstate = _PyThreadState_GET();
+ PyInterpreterState* interp = this_tstate->interp;
+
+ _PyRuntimeState *runtime = &_PyRuntime;
+ HEAD_LOCK(runtime);
+ PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
+ HEAD_UNLOCK(runtime);
+
+ while (ts) {
+ if (_PyEval_SetTrace(ts, func, arg) < 0) {
+ _PyErr_WriteUnraisableMsg("in PyEval_SetTraceAllThreads", NULL);
+ }
+ HEAD_LOCK(runtime);
+ ts = PyThreadState_Next(ts);
+ HEAD_UNLOCK(runtime);
+ }
+}
int
_PyEval_SetCoroutineOriginTrackingDepth(int depth)
diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h
index beaf21c..0f96366 100644
--- a/Python/clinic/sysmodule.c.h
+++ b/Python/clinic/sysmodule.c.h
@@ -292,6 +292,18 @@ exit:
return return_value;
}
+PyDoc_STRVAR(sys__settraceallthreads__doc__,
+"_settraceallthreads($module, arg, /)\n"
+"--\n"
+"\n"
+"Set the global debug tracing function in all running threads belonging to the current interpreter.\n"
+"\n"
+"It will be called on each function call. See the debugger chapter\n"
+"in the library manual.");
+
+#define SYS__SETTRACEALLTHREADS_METHODDEF \
+ {"_settraceallthreads", (PyCFunction)sys__settraceallthreads, METH_O, sys__settraceallthreads__doc__},
+
PyDoc_STRVAR(sys_gettrace__doc__,
"gettrace($module, /)\n"
"--\n"
@@ -312,6 +324,18 @@ sys_gettrace(PyObject *module, PyObject *Py_UNUSED(ignored))
return sys_gettrace_impl(module);
}
+PyDoc_STRVAR(sys__setprofileallthreads__doc__,
+"_setprofileallthreads($module, arg, /)\n"
+"--\n"
+"\n"
+"Set the profiling function in all running threads belonging to the current interpreter.\n"
+"\n"
+"It will be called on each function call and return. See the profiler chapter\n"
+"in the library manual.");
+
+#define SYS__SETPROFILEALLTHREADS_METHODDEF \
+ {"_setprofileallthreads", (PyCFunction)sys__setprofileallthreads, METH_O, sys__setprofileallthreads__doc__},
+
PyDoc_STRVAR(sys_getprofile__doc__,
"getprofile($module, /)\n"
"--\n"
@@ -1170,4 +1194,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored))
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
#define SYS_GETANDROIDAPILEVEL_METHODDEF
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
-/*[clinic end generated code: output=38446a4c76e2f3b6 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=322fb0409e376ad4 input=a9049054013a1b77]*/
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index b8009b2..c286438 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -1022,6 +1022,36 @@ function call. See the debugger chapter in the library manual."
);
/*[clinic input]
+sys._settraceallthreads
+
+ arg: object
+ /
+
+Set the global debug tracing function in all running threads belonging to the current interpreter.
+
+It will be called on each function call. See the debugger chapter
+in the library manual.
+[clinic start generated code]*/
+
+static PyObject *
+sys__settraceallthreads(PyObject *module, PyObject *arg)
+/*[clinic end generated code: output=161cca30207bf3ca input=5906aa1485a50289]*/
+{
+ PyObject* argument = NULL;
+ Py_tracefunc func = NULL;
+
+ if (arg != Py_None) {
+ func = trace_trampoline;
+ argument = arg;
+ }
+
+
+ PyEval_SetTraceAllThreads(func, argument);
+
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
sys.gettrace
Return the global debug tracing function set with sys.settrace.
@@ -1067,6 +1097,35 @@ and return. See the profiler chapter in the library manual."
);
/*[clinic input]
+sys._setprofileallthreads
+
+ arg: object
+ /
+
+Set the profiling function in all running threads belonging to the current interpreter.
+
+It will be called on each function call and return. See the profiler chapter
+in the library manual.
+[clinic start generated code]*/
+
+static PyObject *
+sys__setprofileallthreads(PyObject *module, PyObject *arg)
+/*[clinic end generated code: output=2d61319e27b309fe input=d1a356d3f4f9060a]*/
+{
+ PyObject* argument = NULL;
+ Py_tracefunc func = NULL;
+
+ if (arg != Py_None) {
+ func = profile_trampoline;
+ argument = arg;
+ }
+
+ PyEval_SetProfileAllThreads(func, argument);
+
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
sys.getprofile
Return the profiling function set with sys.setprofile.
@@ -2035,9 +2094,11 @@ static PyMethodDef sys_methods[] = {
SYS_GETSWITCHINTERVAL_METHODDEF
SYS_SETDLOPENFLAGS_METHODDEF
{"setprofile", sys_setprofile, METH_O, setprofile_doc},
+ SYS__SETPROFILEALLTHREADS_METHODDEF
SYS_GETPROFILE_METHODDEF
SYS_SETRECURSIONLIMIT_METHODDEF
{"settrace", sys_settrace, METH_O, settrace_doc},
+ SYS__SETTRACEALLTHREADS_METHODDEF
SYS_GETTRACE_METHODDEF
SYS_CALL_TRACING_METHODDEF
SYS__DEBUGMALLOCSTATS_METHODDEF