[英]How to raise Python exception from a C extension
我想从C扩展中提升KeyboardInterrupt。
在C中,我通过下面的+ setup.py创建了一个名为siginfo
的模块:
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代码中捕获它。
有任何想法吗?
编辑:
我发现我可以通过以下方式引发KeyboardInterrupt:
PyErr_SetString(PyExc_KeyboardInterrupt, "SIGINT received");
但如果我在信号处理程序中提升它,它确实会出错。
如果它在其他功能中被提升,它不会出错。
为什么我不能在信号处理程序中提出它?
在获取信号时,您只是处于执行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);
}
您不能从信号处理程序内部调用任意Python C / API函数。 信号处理程序的功能非常有限。 有关详细信息,请参阅此处和此处 。
Python通过一个非常简单的信号处理程序来处理它,它将volatile sig_atomic_t
类型的变量设置为1.如果设置为1,解释器会定期检查此异常,将Python异常作为常规控制流的一部分。
主要问题是解释器调用需要很长时间才能执行的C代码。 在C代码返回之前不会引发异常。
幸运的是,这种情况并不常发生,因为大多数系统调用在传递信号时都会中断。 在下面的程序中(与你的程序非常相似),对time.sleep()
的调用将被信号中断,控件将返回Python代码,这将引发异常。
import time
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print 'got keybaord interrupt'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.