我使用以下代码在我的C程序中捕获 Ctrl + C :
void sig_handler(int signo)
{
if (signo == SIGINT)
exit(EXIT_SUCCESS);
}
void main ()
{
......
if(signal(SIGINT, sig_handler)== SIG_ERR)
{
printf(">>>>>>>>>>>>>>>>>>>>> SIG INT EROOR !!!! sigint=%d ID=%d \n",SIGINT, getpid());
}
else
printf(">>>>>>>>>>AFTER>>>>>>>>>>> SIG INT sigint=%d PID=%d \n",SIGINT, getpid());
char *buf = NULL;
asprintf(&buf, "%d", getpid());
write(fd, buf, strlen(buf));
free(buf);
uloop_run(); //entering main loop
ubus_exit();
uloop_done();
xml_exit();
config_exit();
free(tmp);
closelog();
log_message(NAME, L_NOTICE, "exiting\n");
return 0;
}
我的目的是捕捉Ctrl + C,但似乎信号处理程序(sig_handler)没有运行!!! 如何解决?
答案 0 :(得分:6)
作为iharob answered,您应该为信号添加处理程序。
但是,您应该仔细阅读signal(7),并注意从信号处理程序内部调用printf
是不合法的(因为printf
不是异步信号 - 安全的功能)。您应该使用write(2)代替printf(3)。
这一限制非常重要。不要忘记,例如printf
和malloc
都可以在任意时刻中断,但它们不是为此而设计的。
至少,请致电fflush(3)和/或以printf
结束您的\n
格式字符串;但那仍然是undefined behavior(但你可能“不幸”让它在大多数时间做你想做的事。)
signal(2)
在实践中,信号处理程序内部的推荐做法是在大多数情况下设置一些volatile sigatomic_t
标志(在处理程序外进行测试)或调用siglongjmp(3)。如果你坚持做其他事情,请确保你只使用(甚至是间接)异步信号安全功能(并且它们很少,主要是syscalls(2) ....)。特别是stdio(3)&永远不应该从信号处理程序中使用malloc(3)(并排除大多数标准C函数或大多数库函数)。
您可能希望在event loop周围有一些poll(2)(那么您可能会对Linux特定的signalfd(2)感兴趣....);你应该编译所有警告和调试信息(gcc -Wall -Wextra -g
)。然后使用gdb
调试器(以及strace(1))来调试程序。
您确定您正在使用的功能(例如uloop_run
等)是否阻止或忽略信号?你应该strace
你的程序找出来!
答案 1 :(得分:4)
您应该使用此函数将处理程序添加到信号中
sighandler_t signal(int signum, sighandler_t handler);
在你的情况下
signal(SIGNINT, sig_handler);
还有一件事,您的main
函数必须返回int
,因此void main()
错误,应为int main()
。
来自OpenWrt的uloop_run
函数为SIGINT
安装信号处理程序,因此无法中断它,并且它会覆盖您的信号处理程序。
这就是为什么永远不会调用信号处理程序的实际原因。
程序不会处理信号,直到uloop_run
函数退出,这是uloop_run
来源及相关部分
static void uloop_setup_signals(bool add)
{
struct sigaction s;
struct sigaction *act, *oldact;
memset(&s, 0, sizeof(struct sigaction));
if (add) {
s.sa_handler = uloop_handle_sigint;
s.sa_flags = 0;
act = &s;
oldact = &org_sighandler;
} else {
act = &org_sighandler;
oldact = NULL;
}
sigaction(SIGINT, act, oldact);
if (uloop_handle_sigchld) {
if (add) {
//act already points to s, so no need to update pointer
s.sa_handler = uloop_sigchld;
oldact = &org_sighandler_child;
} else {
act = &org_sighandler_child;
oldact = NULL;
}
sigaction(SIGCHLD, act, oldact);
}
}
void uloop_run(void)
{
struct timeval tv;
/*
* Handlers are only updated for the first call to uloop_run() (and restored
* when this call is done).
*/
if (!uloop_recursive_count++)
uloop_setup_signals(true);
while(!uloop_cancelled)
{
uloop_gettime(&tv);
uloop_gettime(&tv);
uloop_run_events(uloop_get_next_timeout(&tv));
}
if (!--uloop_recursive_count)
uloop_setup_signals(false);
}
如您所见,uloop_setup_signals(true);
为SIGNINT
安装了一个新的信号处理程序,当循环结束时,uloop_setup_signals(false);
被称为恢复前一个信号处理程序。
所以,这就是原因。