/* Get the state of the current thread: only call this function if the current thread holds the GIL. Raise an exception on error. */ static PyThreadState* get_thread_state(void) { PyThreadState *tstate = _PyThreadState_UncheckedGet(); if (tstate == NULL) { /* just in case but very unlikely... */ PyErr_SetString(PyExc_RuntimeError, "unable to get the current thread state"); return NULL; } return tstate; }
static void faulthandler_dump_traceback(int fd, int all_threads, PyInterpreterState *interp) { static volatile int reentrant = 0; PyThreadState *tstate; if (reentrant) return; reentrant = 1; #ifdef WITH_THREAD /* 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(). */ tstate = PyGILState_GetThisThreadState(); #else tstate = _PyThreadState_UncheckedGet(); #endif if (all_threads) { (void)_Py_DumpTracebackThreads(fd, NULL, tstate); } else { if (tstate != NULL) _Py_DumpTraceback(fd, tstate); } reentrant = 0; }
/* Dump the traceback of all Python threads into fd. Use write() to write the traceback and retry if write() is interrupted by a signal (failed with EINTR), but don't call the Python signal handler. The caller is responsible to call PyErr_CheckSignals() to call Python signal handlers if signals were received. */ const char* _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, 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_tstate = _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) return "unable to get the thread head state"; /* Dump the traceback of each thread */ tstate = PyInterpreterState_ThreadHead(interp); nthreads = 0; _Py_BEGIN_SUPPRESS_IPH do { if (nthreads != 0) PUTS(fd, "\n"); if (nthreads >= MAX_NTHREADS) { PUTS(fd, "...\n"); break; } write_thread_id(fd, tstate, tstate == current_tstate); dump_traceback(fd, tstate, 0); tstate = PyThreadState_Next(tstate); nthreads++; } while (tstate != NULL); _Py_END_SUPPRESS_IPH return NULL; }
PyObject * PyErr_Occurred(void) { PyThreadState *tstate = _PyThreadState_UncheckedGet(); return tstate == NULL ? NULL : tstate->curexc_type; }