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_Get(); #endif if (all_threads) _Py_DumpTracebackThreads(fd, interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(fd, tstate); } reentrant = 0; }
static void faulthandler_user(int signum) { user_signal_t *user; PyThreadState *tstate; int save_errno = errno; user = &user_signals[signum]; if (!user->enabled) return; #ifdef WITH_THREAD /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); #else tstate = PyThreadState_Get(); #endif if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(user->fd, tstate); } #ifdef HAVE_SIGACTION if (user->chain) { (void)sigaction(signum, &user->previous, NULL); errno = save_errno; /* call the previous signal handler */ raise(signum); save_errno = errno; (void)faulthandler_register(signum, user->chain, NULL); errno = save_errno; } #else if (user->chain) { errno = save_errno; /* call the previous signal handler */ user->previous(signum); } #endif }
static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 1; PyThreadState *tstate; const char *errmsg; int fd; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:dump_traceback", kwlist, &file, &all_threads)) return NULL; fd = faulthandler_get_fileno(&file); if (fd < 0) return NULL; tstate = get_thread_state(); if (tstate == NULL) return NULL; if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate); if (errmsg != NULL) { PyErr_SetString(PyExc_RuntimeError, errmsg); return NULL; } } else { _Py_DumpTraceback(fd, tstate); } if (PyErr_CheckSignals()) return NULL; Py_RETURN_NONE; }
static PyObject* faulthandler_dump_traceback_py(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 0; PyThreadState *tstate; const char *errmsg; int fd; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:dump_traceback", kwlist, &file, &all_threads)) return NULL; file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; /* The caller holds the GIL and so PyThreadState_Get() can be used */ tstate = PyThreadState_Get(); if (tstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "unable to get the current thread state"); return NULL; } if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, tstate->interp, tstate); if (errmsg != NULL) { PyErr_SetString(PyExc_RuntimeError, errmsg); return NULL; } } else { _Py_DumpTraceback(fd, tstate); } Py_RETURN_NONE; }
static void faulthandler_user(int signum) { user_signal_t *user; PyThreadState *tstate; user = &user_signals[signum]; if (!user->enabled) return; /* PyThreadState_Get() doesn't give the state of the current thread if the thread doesn't hold the GIL. Read the thread local storage (TLS) instead: call PyGILState_GetThisThreadState(). */ tstate = PyGILState_GetThisThreadState(); if (user->all_threads) _Py_DumpTracebackThreads(user->fd, user->interp, tstate); else { if (tstate == NULL) return; _Py_DumpTraceback(user->fd, tstate); } }
static void faulthandler_fatal_error(int signum) { const int fd = fatal_error.fd; unsigned int i; fault_handler_t *handler = NULL; PyThreadState *tstate; int save_errno = errno; if (!fatal_error.enabled) return; for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; if (handler->signum == signum) break; } if (handler == NULL) { /* faulthandler_nsignals == 0 (unlikely) */ return; } /* restore the previous handler */ #ifdef HAVE_SIGACTION (void)sigaction(signum, &handler->previous, NULL); #else (void)signal(signum, handler->previous); #endif handler->enabled = 0; PUTS(fd, "Fatal Python error: "); PUTS(fd, handler->name); PUTS(fd, "\n\n"); #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_Get(); #endif if (fatal_error.all_threads) _Py_DumpTracebackThreads(fd, fatal_error.interp, tstate); else { if (tstate != NULL) _Py_DumpTraceback(fd, tstate); } errno = save_errno; #ifdef MS_WINDOWS if (signum == SIGSEGV) { /* don't explicitly call the previous handler for SIGSEGV in this signal handler, because the Windows signal handler would not be called */ return; } #endif /* call the previous signal handler: it is called immediatly if we use sigaction() thanks to SA_NODEFER flag, otherwise it is deferred */ raise(signum); }