diff options
author | Pablo Galindo Salgado <Pablogsal@gmail.com> | 2022-08-24 22:21:39 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-24 22:21:39 (GMT) |
commit | e34c82abeb7ace09e6b5d116585c47cc372996c1 (patch) | |
tree | 16f130870af42de041ddf52a36540b9c421aec8c /Python | |
parent | 657976ad950e56b33b7dc15e64a0baecdd184f5a (diff) | |
download | cpython-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.c | 45 | ||||
-rw-r--r-- | Python/clinic/sysmodule.c.h | 26 | ||||
-rw-r--r-- | Python/sysmodule.c | 61 |
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 |