static PyObject* faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 1; int fd; PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:enable", 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; Py_XINCREF(file); Py_XSETREF(fatal_error.file, file); fatal_error.fd = fd; fatal_error.all_threads = all_threads; fatal_error.interp = tstate->interp; if (faulthandler_enable() < 0) { return NULL; } Py_RETURN_NONE; }
static PyObject* faulthandler_register_py(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"signum", "file", "all_threads", "chain", NULL}; int signum; PyObject *file = NULL; int all_threads = 1; int chain = 0; int fd; user_signal_t *user; _Py_sighandler_t previous; PyThreadState *tstate; int err; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|Oii:register", kwlist, &signum, &file, &all_threads, &chain)) return NULL; if (!check_signum(signum)) return NULL; tstate = get_thread_state(); if (tstate == NULL) return NULL; file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; if (user_signals == NULL) { user_signals = PyMem_Malloc(NSIG * sizeof(user_signal_t)); if (user_signals == NULL) return PyErr_NoMemory(); memset(user_signals, 0, NSIG * sizeof(user_signal_t)); } user = &user_signals[signum]; if (!user->enabled) { err = faulthandler_register(signum, chain, &previous); if (err) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } user->previous = previous; } Py_XDECREF(user->file); Py_INCREF(file); user->file = file; user->fd = fd; user->all_threads = all_threads; user->chain = chain; user->interp = tstate->interp; user->enabled = 1; Py_RETURN_NONE; }
static PyObject* faulthandler_dump_traceback_later(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; int timeout; PyOS_sighandler_t previous; int repeat = 0; PyObject *file = NULL; int exit = 0; PyThreadState *tstate; int fd; char *header; size_t header_len; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iOi:dump_traceback_later", kwlist, &timeout, &repeat, &file, &exit)) return NULL; if (timeout <= 0) { PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); return NULL; } tstate = get_thread_state(); if (tstate == NULL) return NULL; fd = faulthandler_get_fileno(&file); if (fd < 0) return NULL; /* format the timeout */ header = format_timeout(timeout); if (header == NULL) return PyErr_NoMemory(); header_len = strlen(header); previous = signal(SIGALRM, faulthandler_alarm); if (previous == SIG_ERR) { PyErr_SetString(PyExc_RuntimeError, "unable to set SIGALRM handler"); free(header); return NULL; } Py_XDECREF(fault_alarm.file); Py_XINCREF(file); fault_alarm.file = file; fault_alarm.fd = fd; fault_alarm.timeout = timeout; fault_alarm.repeat = repeat; fault_alarm.interp = tstate->interp; fault_alarm.exit = exit; fault_alarm.header = header; fault_alarm.header_len = header_len; alarm(timeout); Py_RETURN_NONE; }
static PyObject* faulthandler_dump_traceback_later(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; double timeout; PY_TIMEOUT_T timeout_ms; int repeat = 0; PyObject *file = NULL; int fd; int exit = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d|iOi:dump_tracebacks_later", kwlist, &timeout, &repeat, &file, &exit)) return NULL; timeout *= 1e6; if (timeout >= (double) PY_TIMEOUT_MAX) { PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); return NULL; } timeout_ms = (PY_TIMEOUT_T)timeout; if (timeout_ms <= 0) { PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); return NULL; } file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; /* Cancel previous thread, if running */ faulthandler_cancel_dump_tracebacks_later(); Py_XDECREF(thread.file); Py_INCREF(file); thread.file = file; thread.fd = fd; thread.timeout_ms = timeout_ms; thread.repeat = repeat; thread.interp = PyThreadState_Get()->interp; thread.exit = exit; /* Arm these locks to serve as events when released */ PyThread_acquire_lock(thread.join_event, 1); PyThread_acquire_lock(thread.cancel_event, 1); thread.running = 1; if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { thread.running = 0; PyThread_release_lock(thread.join_event); PyThread_release_lock(thread.cancel_event); Py_CLEAR(thread.file); PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); return NULL; } Py_RETURN_NONE; }
PyObject* faulthandler_dumpbacktrace_later(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"delay", "repeat", "file", "all_threads", NULL}; int delay; PyOS_sighandler_t previous; int repeat = 0; PyObject *file = NULL; int all_threads = 0; int fd; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iOi:dump_backtrace_later", kwlist, &delay, &repeat, &file, &all_threads)) return NULL; if (delay <= 0) { PyErr_SetString(PyExc_ValueError, "delay must be greater than 0"); return NULL; } if (file == NULL || file == Py_None) { file = PySys_GetObject("stderr"); if (file == NULL) { PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr"); return NULL; } } fd = faulthandler_get_fileno(file); if (fd == -1) return NULL; previous = signal(SIGALRM, faulthandler_alarm); if (previous == SIG_ERR) { PyErr_SetString(PyExc_RuntimeError, "unable to set SIGALRM handler"); return NULL; } Py_INCREF(file); fault_alarm.file = file; fault_alarm.fd = fd; fault_alarm.delay = delay; fault_alarm.repeat = repeat; fault_alarm.all_threads = all_threads; alarm(delay); 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 = 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 PyObject* faulthandler_dump_tracebacks_later(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"timeout", "repeat", "file", "exit", NULL}; double timeout; PY_TIMEOUT_T timeout_us; int repeat = 0; PyObject *file = NULL; int fd; int exit = 0; PyThreadState *tstate; char *header; size_t header_len; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d|iOi:dump_tracebacks_later", kwlist, &timeout, &repeat, &file, &exit)) return NULL; if ((timeout * 1e6) >= (double) PY_TIMEOUT_MAX) { PyErr_SetString(PyExc_OverflowError, "timeout value is too large"); return NULL; } timeout_us = (PY_TIMEOUT_T)(timeout * 1e6); if (timeout_us <= 0) { PyErr_SetString(PyExc_ValueError, "timeout must be greater than 0"); return NULL; } tstate = get_thread_state(); if (tstate == NULL) return NULL; file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; /* format the timeout */ header = format_timeout(timeout); if (header == NULL) return PyErr_NoMemory(); header_len = strlen(header); /* Cancel previous thread, if running */ cancel_dump_tracebacks_later(); Py_XDECREF(thread.file); Py_INCREF(file); thread.file = file; thread.fd = fd; thread.timeout_us = timeout_us; thread.repeat = repeat; thread.interp = tstate->interp; thread.exit = exit; thread.header = header; thread.header_len = header_len; /* Arm these locks to serve as events when released */ PyThread_acquire_lock(thread.running, 1); if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) { PyThread_release_lock(thread.running); Py_CLEAR(thread.file); free(header); thread.header = NULL; PyErr_SetString(PyExc_RuntimeError, "unable to start watchdog thread"); return NULL; } Py_RETURN_NONE; }
static PyObject* faulthandler_enable(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"file", "all_threads", NULL}; PyObject *file = NULL; int all_threads = 1; unsigned int i; fault_handler_t *handler; #ifdef HAVE_SIGACTION struct sigaction action; #endif int err; int fd; PyThreadState *tstate; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:enable", kwlist, &file, &all_threads)) return NULL; file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; tstate = get_thread_state(); if (tstate == NULL) return NULL; Py_XDECREF(fatal_error.file); Py_INCREF(file); fatal_error.file = file; fatal_error.fd = fd; fatal_error.all_threads = all_threads; fatal_error.interp = tstate->interp; if (!fatal_error.enabled) { fatal_error.enabled = 1; for (i=0; i < faulthandler_nsignals; i++) { handler = &faulthandler_handlers[i]; #ifdef HAVE_SIGACTION action.sa_handler = faulthandler_fatal_error; sigemptyset(&action.sa_mask); /* Do not prevent the signal from being received from within its own signal handler */ action.sa_flags = SA_NODEFER; #ifdef HAVE_SIGALTSTACK if (stack.ss_sp != NULL) { /* Call the signal handler on an alternate signal stack provided by sigaltstack() */ action.sa_flags |= SA_ONSTACK; } #endif err = sigaction(handler->signum, &action, &handler->previous); #else handler->previous = signal(handler->signum, faulthandler_fatal_error); err = (handler->previous == SIG_ERR); #endif if (err) { PyErr_SetFromErrno(PyExc_RuntimeError); return NULL; } handler->enabled = 1; } } Py_RETURN_NONE; }
static PyObject* faulthandler_register(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"signum", "file", "all_threads", NULL}; int signum; PyObject *file = NULL; int all_threads = 0; int fd; user_signal_t *user; _Py_sighandler_t previous; #ifdef HAVE_SIGACTION struct sigaction action; #endif PyThreadState *tstate; int err; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|Oi:register", kwlist, &signum, &file, &all_threads)) return NULL; if (!check_signum(signum)) 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; } file = faulthandler_get_fileno(file, &fd); if (file == NULL) return NULL; if (user_signals == NULL) { user_signals = calloc(NSIG, sizeof(user_signal_t)); if (user_signals == NULL) return PyErr_NoMemory(); } user = &user_signals[signum]; if (!user->enabled) { #ifdef HAVE_SIGACTION action.sa_handler = faulthandler_user; sigemptyset(&action.sa_mask); /* if the signal is received while the kernel is executing a system call, try to restart the system call instead of interrupting it and return EINTR */ action.sa_flags = SA_RESTART; #ifdef HAVE_SIGALTSTACK if (stack.ss_sp != NULL) { /* Call the signal handler on an alternate signal stack provided by sigaltstack() */ action.sa_flags |= SA_ONSTACK; } #endif err = sigaction(signum, &action, &previous); #else previous = signal(signum, faulthandler_user); err = (previous == SIG_ERR); #endif if (err) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } } Py_XDECREF(user->file); Py_INCREF(file); user->file = file; user->fd = fd; user->all_threads = all_threads; user->previous = previous; user->interp = tstate->interp; user->enabled = 1; Py_RETURN_NONE; }