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:
Victor Stinner 2016-03-16 22:45:24 +01:00
parent c36674a2c5
commit 861d9abfcf
7 changed files with 164 additions and 48 deletions

View file

@ -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,

View file

@ -714,6 +714,12 @@ _PyGILState_Init(PyInterpreterState *i, PyThreadState *t)
_PyGILState_NoteThreadState(t);
}
PyInterpreterState *
_PyGILState_GetInterpreterStateUnsafe(void)
{
return autoInterpreterState;
}
void
_PyGILState_Fini(void)
{

View file

@ -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++;