信号处理之自动重启系统调用

来源:互联网 发布:三维机房设计软件 编辑:程序博客网 时间:2024/05/21 20:28

       一般来说,不会阻塞的系统调用不存在被信号打断的问题,就是说返回的errno里面不存在EINTR错误,阻塞的系统调用才有可能被信号打断。我们可以看看man page,在linux下输入man 7 signal,我们可以看到系统调用被打断以及系统调用重启的详细描述: 

      

       上面一大段说的就是哪些系统调用会被信号打断以及SA_RESTART标志被设置后,系统调用是否自动重启的描述。上面说的很清楚,有些系统调用不管你是否设置了SA_RESTART标志,直接返回错误EINTR,例如:epoll_wait、select之类的;有些系统调用在满足一定条件下才会自动重启,例如:Socket API函数,要在没有调用setsockopt设置超时选项的时候,才会自动重启(如果SA_RESTART被设置)。

       好了,那么我们来总结一下,在做信号捕获和处理的时候,设置了SA_RESTART,系统调用才有可能重启,如果压根就没有做信号捕获或者没有设置SA_RESTART,则根本就不存在系统调用自动重启问题,默认都是直接返回错误。我们可以写一个简单的程序来测试系统调用自动重启,毕竟眼见为实,跑一遍程序就更有体会。

#include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>static void int_hander(int s){printf("Catch a signal sigint\n");}int main(void){char buf[1024];memset(buf, 0, sizeof(buf));struct sigaction act, oact;act.sa_handler = int_hander;sigemptyset(&act. sa_mask); //清空此信号集act.sa_flags = SA_RESTART;sigaction(SIGINT, &act, &oact);read(STDIN_FILENO,buf,sizeof(buf)-1);printf("read from stdin: %s", buf);sigaction(SIGINT, &oact, NULL); //恢复成原始状态return 0;}

       可以在机器上编译程序,然后运行,只要终端没有输入字符,程序就会一直挂着,按Ctrl+C,会触发SIGINT信号,也就说会打印:Catch a signal sigint。然后程序又睡眠了,说明我们的系统调用read自动重启了。如果把SA_RESTART标志去掉,我们可以看到另外一种效果,触发SIGINT信号后,打印:Catch a signal sigint,然后就退出了,说明read系统调用没有自动重启。我们就验证了man page里面的说法。

       总结:从实用性角度来讲,这个SA_RESTART标志其实没有什么用,因为系统调用自动重启其实是不安全的,还是重新调用一次系统调用可控性比较好。而且我们不能保证所有能被捕获的信号都被捕获而且设置了SA_RESTART标志,只要有一个信号忘记处理了,足以打断系统调用。

0 0