diff options
author | Julien Danjou <julien@danjou.info> | 2020-11-02 15:16:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-02 16:16:25 +0200 |
commit | 64366fa9b3ba71b8a503a8719eff433f4ea49eb9 (patch) | |
tree | 8aa6d76484553d2f29bfe5d03709a86c0abe547f /Python/pystate.c | |
parent | 3d86d090dcbbdfdd3e5a5951cab30612d6131222 (diff) | |
download | cpython-64366fa9b3ba71b8a503a8719eff433f4ea49eb9.tar.gz cpython-64366fa9b3ba71b8a503a8719eff433f4ea49eb9.zip |
bpo-41435: Add sys._current_exceptions() function (GH-21689)
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.
Diffstat (limited to 'Python/pystate.c')
-rw-r--r-- | Python/pystate.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/Python/pystate.c b/Python/pystate.c index e88898670cd..e37cbd5a657 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1222,6 +1222,69 @@ done: return result; } +PyObject * +_PyThread_CurrentExceptions(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + + _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); + 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); + 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 |