Как вызвать исключение Python из расширения C

Я хотел бы поднять KeyboardInterrupt из расширения C.

В C я создал модуль с именем siginfo с помощью ниже + setup.py:

static void siginfo_handler(int signum, siginfo_t *siginfo, void *context) {
    printf("got signal from '%d'", siginfo->si_pid);

    //raise(PyExc_KeyboardInterrupt) <--- i want to raise keyboard interrupt here
}

static PyObject * siginfo_register(PyObject *self, PyObject *args) {
    struct sigaction act;
    memset(&act, '\0', sizeof(act));
    act.sa_sigaction = &siginfo_handler;
    act.sa_flags = SA_SIGINFO;
    sigaction(SIGINT, &act, NULL);

    PY_RETURN_NONE;
}

static PyMethodDef SiginfoMethods[] = {
   //blah blah filled out
};
PyMODINIT_FUNC initsiginfo(void) {
   //blah blah filled out
}

В Python:

import siginfo
import os
siginfo.register()

print "talk to me with kill -SIGINT %d" % os.getpid()

try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    print 'got keybaord interrupt'

Расширение C прекрасно ловит SIGINT, но я не знаю, как вызвать из него исключение Python, чтобы я мог перехватить его в коде Python.

Есть идеи?

EDIT:
Я обнаружил, что могу повысить KeyboardInterrupt следующим образом:

PyErr_SetString(PyExc_KeyboardInterrupt, "SIGINT received");

но это вызывает ошибку, если я поднимаю ее в обработчике сигнала.

он не вызывает ошибку, если он вызван в другой функции.

Почему я не могу поднять его в обработчике сигналов?

4 голоса | спросил ealeon 5 42015vEurope/Moscow11bEurope/MoscowThu, 05 Nov 2015 21:45:14 +0300 2015, 21:45:14

2 ответа


0

Вы просто не в состоянии выполнить код Python при получении сигнала. Перед появлением ошибки вам необходимо приобрести GIL :

static void siginfo_handler(int signum, siginfo_t *siginfo, void *context) {
    printf("got signal from '%d'\n", siginfo->si_pid);
    PyGILState_STATE gstate = PyGILState_Ensure();
    PyErr_SetString(PyExc_KeyboardInterrupt, "SIGINT received");
    PyGILState_Release(gstate);
}
ответил tynn 7 62015vEurope/Moscow11bEurope/MoscowSat, 07 Nov 2015 21:30:58 +0300 2015, 21:30:58
0

Вы не можете вызывать произвольные функции Python C /API из обработчика сигнала. Обработчики сигналов чрезвычайно ограничены в своих возможностях. См. здесь и здесь для получения дополнительной информации.

Python справляется с этим, имея очень простой обработчик сигнала, который устанавливает переменную типа volatile sig_atomic_t в 1. Эта переменная периодически проверяется интерпретатор вызывает исключение Python как часть обычного потока управления, если оно установлено в 1.

Основная проблема заключается в том, что интерпретатор вызывает код C, выполнение которого занимает много времени. Исключение не будет вызываться до тех пор, пока код C не вернется.

К счастью, это происходит не слишком часто, потому что большинство системных вызовов прерываются при доставке сигнала. В следующей программе (очень похожей на вашу) вызов time.sleep() будет прерван сигналом, и управление вернется к коду Python что вызовет исключение.

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    print 'got keybaord interrupt'
ответил sterin 8 72015vEurope/Moscow11bEurope/MoscowSun, 08 Nov 2015 14:13:33 +0300 2015, 14:13:33

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132