-
-
Notifications
You must be signed in to change notification settings - Fork 32k
GH-93503: Add thread-specific APIs to set profiling and tracing functions in the C-API #93504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
10d7746
b3a223f
438eae6
5cbcaa1
b3333d8
d580e5d
05bf74c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
Add two new public functions to the public C-API, | ||
:c:func:`PyEval_SetProfileAllThreads` and | ||
:c:func:`PyEval_SetTraceAllThreads`, that allow to set tracking and | ||
profiling functions in all running threads in addition to the calling one. | ||
Also, add a new *running_threads* parameter to :func:`threading.setprofile` | ||
and :func:`threading.settrace` that allows to do the same from Python. Patch | ||
by Pablo Galindo |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not great that the function cannot report errors. While not returning -1 on error and pass the exception to the caller, rather than handling it with _PyErr_WriteUnraisableMsg()? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am mimicking what we do already in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We cannot fix the API of old functions, but we can avoid past mistakes in newly added functions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to ignore exceptions on purpose, please mention it in the function documentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah, I want to do that because I don't want to stop setting the profile function on other threads if an exception in one fails. Unless you strongly disagree, I will document this. |
||
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); | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
HEAD_UNLOCK(runtime); | ||
} | ||
} | ||
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
pablogsal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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) | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.