-
-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
bpo-41435: Add sys._current_exceptions() function #21689
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
This adds a new function named sys._current_exceptions() which is equivalent ot sys._current_frames() except that it returns the exceptions currently handled by other threads. It is equivalent to calling sys.exc_info() for each running thread.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add `sys._current_exceptions()` function to retrieve a dictionary mapping each thread's identifier to the topmost exception currently active in that thread at the time the function is called. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1200,6 +1200,69 @@ _PyThread_CurrentFrames(void) | |
return result; | ||
} | ||
|
||
PyObject * | ||
_PyThread_CurrentExceptions(void) | ||
{ | ||
PyThreadState *tstate = _PyThreadState_GET(); | ||
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 would prefer to ensure that the GIL is held. For example, call _Py_EnsureTstateNotNULL(tstate). 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. Done. |
||
|
||
_Py_EnsureTstateNotNULL(tstate); | ||
|
||
if (_PySys_Audit(tstate, "sys._current_exceptions", NULL) < 0) { | ||
return NULL; | ||
} | ||
|
||
PyObject *result = PyDict_New(); | ||
if (result == NULL) { | ||
return NULL; | ||
} | ||
|
||
/* for i in all interpreters: | ||
* for t in all of i's thread states: | ||
* if t's frame isn't NULL, map t's id to its frame | ||
* Because these lists can mutate even when the GIL is held, we | ||
* need to grab head_mutex for the duration. | ||
*/ | ||
_PyRuntimeState *runtime = tstate->interp->runtime; | ||
HEAD_LOCK(runtime); | ||
PyInterpreterState *i; | ||
for (i = runtime->interpreters.head; i != NULL; i = i->next) { | ||
PyThreadState *t; | ||
for (t = i->tstate_head; t != NULL; t = t->next) { | ||
_PyErr_StackItem *err_info = _PyErr_GetTopmostException(t); | ||
if (err_info == NULL) { | ||
continue; | ||
} | ||
PyObject *id = PyLong_FromUnsignedLong(t->thread_id); | ||
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. A single thread can be associated to more than one Python thread state. It is possible that two interpreters run in the same thread, just not at the same time. 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. This is also a limitation in |
||
if (id == NULL) { | ||
goto fail; | ||
} | ||
PyObject *exc_info = PyTuple_Pack( | ||
3, | ||
err_info->exc_type != NULL ? err_info->exc_type : Py_None, | ||
err_info->exc_value != NULL ? err_info->exc_value : Py_None, | ||
err_info->exc_traceback != NULL ? err_info->exc_traceback : Py_None); | ||
if (exc_info == NULL) { | ||
Py_DECREF(id); | ||
goto fail; | ||
} | ||
int stat = PyDict_SetItem(result, id, exc_info); | ||
jd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Py_DECREF(id); | ||
Py_DECREF(exc_info); | ||
if (stat < 0) { | ||
goto fail; | ||
} | ||
} | ||
} | ||
goto done; | ||
|
||
fail: | ||
Py_CLEAR(result); | ||
|
||
done: | ||
HEAD_UNLOCK(runtime); | ||
return result; | ||
} | ||
|
||
/* Python "auto thread state" API. */ | ||
|
||
/* Keep this as a static, as it is not reliable! It can only | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not clear that threads with no exception are omitted in this dictionary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.