在c程序中捕获Ctrl + c

时间:2014-12-23 13:57:38

标签: c linux openwrt

我使用以下代码在我的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)没有运行!!! 如何解决?

2 个答案:

答案 0 :(得分:6)

作为iharob answered,您应该为信号添加处理程序。

但是,您应该仔细阅读signal(7),并注意从信号处理程序内部调用printf是不合法的(因为printf不是异步信号 - 安全的功能)。您应该使用write(2)代替printf(3)

这一限制非常重要。不要忘记,例如printfmalloc都可以在任意时刻中断,但它们不是为此而设计的。

至少,请致电fflush(3)和/或以printf结束您的\n格式字符串;但那仍然是undefined behavior(但你可能“不幸”让它在大多数时间做你想做的事。)

顺便说一句,今天建议使用sigaction(2)代替“过时的”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()

来自OpenWrtuloop_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);被称为恢复前一个信号处理程序。

所以,这就是原因。

相关问题