mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
faulthandler now works in non-Python threads
Issue #26563: * Add _PyGILState_GetInterpreterStateUnsafe() function: the single PyInterpreterState used by this process' GILState implementation. * Enhance _Py_DumpTracebackThreads() to retrieve the interpreter state from autoInterpreterState in last resort. The function now accepts NULL for interp and current_tstate parameters. * test_faulthandler: fix a ResourceWarning when test is interrupted by CTRL+c
This commit is contained in:
parent
c36674a2c5
commit
861d9abfcf
7 changed files with 164 additions and 48 deletions
|
@ -1275,25 +1275,11 @@ initstdio(void)
|
|||
static void
|
||||
_Py_FatalError_DumpTracebacks(int fd)
|
||||
{
|
||||
PyThreadState *tstate;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
/* PyGILState_GetThisThreadState() works even if the GIL was released */
|
||||
tstate = PyGILState_GetThisThreadState();
|
||||
#else
|
||||
tstate = PyThreadState_GET();
|
||||
#endif
|
||||
if (tstate == NULL) {
|
||||
/* _Py_DumpTracebackThreads() requires the thread state to display
|
||||
* frames */
|
||||
return;
|
||||
}
|
||||
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
|
||||
/* display the current Python stack */
|
||||
_Py_DumpTracebackThreads(fd, tstate->interp, tstate);
|
||||
_Py_DumpTracebackThreads(fd, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Print the current exception (if an exception is set) with its traceback,
|
||||
|
|
|
@ -714,6 +714,12 @@ _PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
|
|||
_PyGILState_NoteThreadState(t);
|
||||
}
|
||||
|
||||
PyInterpreterState *
|
||||
_PyGILState_GetInterpreterStateUnsafe(void)
|
||||
{
|
||||
return autoInterpreterState;
|
||||
}
|
||||
|
||||
void
|
||||
_PyGILState_Fini(void)
|
||||
{
|
||||
|
|
|
@ -707,11 +707,56 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
|||
handlers if signals were received. */
|
||||
const char*
|
||||
_Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||
PyThreadState *current_thread)
|
||||
PyThreadState *current_tstate)
|
||||
{
|
||||
PyThreadState *tstate;
|
||||
unsigned int nthreads;
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
if (current_tstate == NULL) {
|
||||
/* _Py_DumpTracebackThreads() is called from signal handlers by
|
||||
faulthandler.
|
||||
|
||||
SIGSEGV, SIGFPE, SIGABRT, SIGBUS and SIGILL are synchronous signals
|
||||
and are thus delivered to the thread that caused the fault. Get the
|
||||
Python thread state of the current thread.
|
||||
|
||||
PyThreadState_Get() doesn't give the state of the thread that caused
|
||||
the fault if the thread released the GIL, and so this function
|
||||
cannot be used. Read the thread local storage (TLS) instead: call
|
||||
PyGILState_GetThisThreadState(). */
|
||||
current_tstate = PyGILState_GetThisThreadState();
|
||||
}
|
||||
|
||||
if (interp == NULL) {
|
||||
if (current_tstate == NULL) {
|
||||
interp = _PyGILState_GetInterpreterStateUnsafe();
|
||||
if (interp == NULL) {
|
||||
/* We need the interpreter state to get Python threads */
|
||||
return "unable to get the interpreter state";
|
||||
}
|
||||
}
|
||||
else {
|
||||
interp = current_tstate->interp;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (current_tstate == NULL) {
|
||||
/* Call _PyThreadState_UncheckedGet() instead of PyThreadState_Get()
|
||||
to not fail with a fatal error if the thread state is NULL. */
|
||||
current_thread = _PyThreadState_UncheckedGet();
|
||||
}
|
||||
|
||||
if (interp == NULL) {
|
||||
if (current_tstate == NULL) {
|
||||
/* We need the interpreter state to get Python threads */
|
||||
return "unable to get the interpreter state";
|
||||
}
|
||||
interp = current_tstate->interp;
|
||||
}
|
||||
#endif
|
||||
assert(interp != NULL);
|
||||
|
||||
/* Get the current interpreter from the current thread */
|
||||
tstate = PyInterpreterState_ThreadHead(interp);
|
||||
if (tstate == NULL)
|
||||
|
@ -729,7 +774,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
|||
PUTS(fd, "...\n");
|
||||
break;
|
||||
}
|
||||
write_thread_id(fd, tstate, tstate == current_thread);
|
||||
write_thread_id(fd, tstate, tstate == current_tstate);
|
||||
dump_traceback(fd, tstate, 0);
|
||||
tstate = PyThreadState_Next(tstate);
|
||||
nthreads++;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue