Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}