summaryrefslogtreecommitdiffstats
path: root/Python/traceback.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2016-03-16 21:45:24 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2016-03-16 21:45:24 (GMT)
commit861d9abfcf6a4a34790e4edc5e440a68534137e1 (patch)
treea4ea3ef14a2f0494743733b9db4079f27f5906ca /Python/traceback.c
parentc36674a2c52ecb30e180b3bcced2b8c529cf72fb (diff)
downloadcpython-861d9abfcf6a4a34790e4edc5e440a68534137e1.zip
cpython-861d9abfcf6a4a34790e4edc5e440a68534137e1.tar.gz
cpython-861d9abfcf6a4a34790e4edc5e440a68534137e1.tar.bz2
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
Diffstat (limited to 'Python/traceback.c')
-rw-r--r--Python/traceback.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/Python/traceback.c b/Python/traceback.c
index 8383c16..403dba5 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -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++;