关于信号中断与慢系统调用的深度发现
来源:互联网 发布:腾龙网络秋个人珍藏 编辑:程序博客网 时间:2024/05/22 17:20
这段时间在看Unix网络编程卷1,在5.9节处理SIGCHLD信号,关于处理僵死进程第四步如下写道:信号是在父进程阻塞于慢系统调用(accept)时由父进程捕获的,内核就会使慢系统调用(accept)返回一个EINTR错误。
看到上面那段落的时候,想到我前段时间写网络服务器遇到的问题,链接地址:http://bbs.csdn.net/topics/391032981,其实里面也有我关于这方面问题的困惑。
总结一下我论坛的那个问题,其实我无论如何是不能通过信号中断,测试epoll_wait出错errno置EINTR进而执行程序退出的,说个很简单的理由,当选用IDE进行调试程序的时候,若程序增加的有断点,程序会在步入断点的时候接收到SIGTRAP信号,这样一样会使慢系统调用返回错误并置errno为EINTR,这个时候的我肯定是不想程序就此退出。当然那个问题后来我是通过SocketPair解决的,其一用于epoll_wait监听,另一个在需要退出的时候写入数据,epoll_wait返回的时候,首先判断用于监听的那个套接字是否需要接收数据,若有数据需要接收那就是我通知程序退出呢。
接下来关于信号中断与慢系统调用的两个测试,测试环境Centos7 64,所有代码均无错误处理,请自行包含相关头文件
void sig_func(int signo){printf("catch %d\n", signo);}int main(int argc, char *argv[]){signal(SIGINT, sig_func);int lfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(1234);inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);bind(lfd, (struct sockaddr *)&addr, sizeof(addr));listen(lfd, 10);while (true) {struct sockaddr_in caddr;socklen_t len = sizeof(caddr);int cfd = accept(lfd, (struct sockaddr *)&caddr, &len);printf("accept %d\n", cfd);}}
多次Ctrl+C,程序作如下输出:
[root@bogon Debug]# ./server ^Ccatch 2^Ccatch 2现像是通过Ctrl+C产生中断,并不会使accept函数返回,这和我们预想的不一样啊,这可能就是因为系统的signal已如Unix网络编程书中所说的那样,默认增加了自动重启这个标志,这时只能求助于手册,手册中有如此写道:
Furthermore, certain blocking system calls are automatically restarted if interrupted by a signal handler (see signal(7)). The BSD semantics are equivalent to calling sigaction(2) with the following flags: sa.sa_flags = SA_RESTART;
void sig_func(int signo){printf("catch %d\n", signo);}int main(int argc, char *argv[]){signal(SIGINT, sig_func);int lfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(1234);inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);bind(lfd, (struct sockaddr *)&addr, sizeof(addr));listen(lfd, 10);fd_set fds;FD_ZERO(&fds);FD_SET(lfd, &fds);int res = select(lfd+1, &fds, NULL, NULL, NULL);printf("select %d -- errno %d\n", res, errno);}单次Ctrl+C,程序作如下输出:
[root@bogon Debug]# ./server ^Ccatch 2select -1 -- errno 4
代码其实基本还是上面的代码,只是将想验证的系统调用换成了select调用,这个又和我们预想的一样,但是若真如我们手册中看到那样,这又是错误的啦,这时我们只能再次求助于帮助手册,又好好翻了翻手册,终于找到原因啦。
Interruption of system calls and library functions by signal handlers If a signal handler is invoked while a system call or library function call is blocked, then either: * the call is automatically restarted after the signal handler returns; or * the call fails with the error EINTR. Which of these two behaviors occurs depends on the interface and whether or not the signal handler was established using the SA_RESTART flag (see sigaction(2)). The details vary across UNIX systems; below, the details for Linux. If a blocked call to one of the following interfaces is interrupted by a signal handler, then the call will be automatically restarted after the signal handler returns if the SA_RESTART flag was used; otherwise the call will fail with the error EINTR: * read(2), readv(2), write(2), writev(2), and ioctl(2) calls on "slow" devices. A "slow" device is one where the I/O call may block for an indefinite time, for example, a terminal, pipe, or socket. (A disk is not a slow device according to this definition.) If an I/O call on a slow device has already transferred some data by the time it is interrupted by a signal handler, then the call will return a success status (normally, the number of bytes transferred). * open(2), if it can block (e.g., when opening a FIFO; see fifo(7)). * wait(2), wait3(2), wait4(2), waitid(2), and waitpid(2). * Socket interfaces: accept(2), connect(2), recv(2), recvfrom(2), recvmsg(2), send(2), sendto(2), and sendmsg(2), unless a timeout has been set on the socket (see below). * File locking interfaces: flock(2) and fcntl(2) F_SETLKW. * POSIX message queue interfaces: mq_receive(3), mq_timedreceive(3), mq_send(3), and mq_timedsend(3). * futex(2) FUTEX_WAIT (since Linux 2.6.22; beforehand, always failed with EINTR). * POSIX semaphore interfaces: sem_wait(3) and sem_timedwait(3) (since Linux 2.6.22; beforehand, always failed with EINTR). The following interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler: * Socket interfaces, when a timeout has been set on the socket using setsockopt(2): accept(2), recv(2), recvfrom(2), and recvmsg(2), if a receive timeout (SO_RCVTIMEO) has been set; connect(2), send(2), sendto(2), and sendmsg(2), if a send timeout (SO_SNDTIMEO) has been set. * Interfaces used to wait for signals: pause(2), sigsuspend(2), sigtimedwait(2), and sigwaitinfo(2). * File descriptor multiplexing interfaces: epoll_wait(2), epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2). * System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and semtimedop(2). * Sleep interfaces: clock_nanosleep(2), nanosleep(2), and usleep(3). * read(2) from an inotify(7) file descriptor. * io_getevents(2). The sleep(3) function is also never restarted if interrupted by a handler, but gives a success return: the number of seconds remaining to sleep.这里大致说明一下就是:当一个信号被捕获处理的时正阻塞着系统调用或是库函数,将会有两种情况发生,一种是调用将会自动重启当信号处理函数返回的时候,另一种是调用失败返回errno置EINTR。因为signal默认增加SA_RESTART标志,所以上面的是中断因为有标志自动重启的,下面的是无论如何都会返回错误的。
经过测试,若自己通过sigaction函数提供Signal函数调用,并在函数中取消SA_RESTART标志,这样的话,第一个测试程序将会有如下输出:
[root@bogon Debug]# ./server sigaction successed.^Ccatch 2accept -1^Ccatch 2accept -1关于Signal函数这里不再实现。
这里我们就不再验证epoll_wait,因为根据论坛提的问题来看,epoll_wait也是会返回错误的。至于为什么在多线程的时候某种情况下就不会返回,这就要牵涉到捕获信号的机制了吧,相关书籍我没有看过,我这里用不太准确的话描述一下,就是若假定程序有两个线程,主线程启动,执行signal捕获信号(这里是主线程执行该语句哦),另一个线程执行epoll_wait,这个时候若产生信号,将会由主线程负责捕获和处理所有信号,这对另一个线程没有产生任何影响,所以epoll_wait才不会返回的。总结性来说,多线程中只会有一个线程来捕获和处理信号。
- 关于信号中断与慢系统调用的深度发现
- 慢系统调用与信号中断
- 信号中断 与 慢系统调用
- 信号中断 与 慢系统调用
- 信号中断 与 慢系统调用
- 慢系统调用与信号中断(转)
- 信号中断 与 慢系统调用
- 信号中断 与 慢系统调用
- 信号中断 与 慢系统调用
- 慢系统调用的中断与重启
- 10.5 信号_中断的系统调用
- linux 信号 中断的系统调用
- 信号 中断系统调用 递送
- 信号 中断系统调用 递送
- linux网络编程---慢系统调用和中断信号EINTR
- linux网络编程之慢系统调用被信号中断产生EINTR错误怎么解决总结
- 系统调用与中断
- Linux环境编程之信号(二):不可靠信号、中断的系统调用、可重入函数
- 【OC 第3课】NSString ,NSMutableString用法以及一些常用方法
- iOS项目开发实战——视图动画效果
- java正则中REGEX = "[\u4e00-\u9fa5]的意思?
- Linux查看物理CPU个数、核数、逻辑CPU个数
- 枚举思想
- 关于信号中断与慢系统调用的深度发现
- 一款功能强大的iphone购物应用源码
- unity和委托
- 一位初入门的新员工的代码分析(2)
- 分治思想
- 最短路
- 回溯思想
- CentOS 安装FTP服务
- 借助江苏电信欢go进行流量推广活动合作的工作规范(二)