2015-11-05 3 views
3

Я хотел бы поднять KeyboardInterrupt с расширения C.Как поднять исключение Python из расширения 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"); 

но это сегментный вина, если я поднять его в обработчик сигнала.

это не seg неисправность если поднят в другой функции.

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

+3

Я не уверен, что вы можете заставить это работать. Конечно, не из обработчика сигнала. –

+1

@ IgnacioVazquez-Abrams это, безусловно, работает от обработчика сигнала. – tynn

ответ

2

Вы просто не в состоянии выполнить код 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); 
} 
+1

Это не работает надежно. Он работает большую часть времени, но он почти гарантирует непредсказуемые и невоспроизводимые проблемы и сбои. Обработчикам сигналов разрешено вызывать [асинхронные сигнальные функции] (http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html). Обработчики сигналов не должны выделять память или даже вызывать 'printf()'. Обработчики сигналов обязательно не должны вызывать Python C/API, если это специально не разрешено. – sterin

+0

это отлично работает для меня. у havent были какие-то проблемы. но я беспокоюсь о том, что говорится выше. Я не совсем понимаю это, хотя @ user99279 – ealeon

+0

@ealeon Python имеет [библиотеку] (https://docs.python.org/2/library/signal.html) для установки обработчика сигнала. Возможно, используйте это вместо этого. Это может быть немного больше работы, но безопаснее. – tynn

0

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

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' 

 Смежные вопросы

  • Нет связанных вопросов^_^