分类: C/C++
2017-09-08 17:28:13
我们经常在网络编程中会看到这样,当执行一个可能会阻塞的系统调用后,在返回的时候需要检查下错误码(if errno == EINTR),如果是这样的错误,那我们一般会重新执行该系统调用。所以经常的写法是:
repeat:
if(read(fd, buff, size) < 0)
{
if(errno == EINTR)
goto repeat;
else
printf("read failed");
}
但一般我们在读/写磁盘文件的时候却不太会判断这个错误,那我们到底什么时候该判断而什么时候又不要去判断呢?这是个问题。针对这个问题我特意做了一些测试。首先是读磁盘文件,测试代码如下:
#define _GNU_SOURCE #include#include #include #include #include #include #include #include #include void hup_handler(int sig) { printf("."); fflush(stdout); } int main() { int i = 0; struct sigaction act; const int buffSize = 1 << 27; int allocated = 0; char* buf = NULL; act.sa_handler = hup_handler; act.sa_flags = SA_INTERRUPT; sigemptyset(&act.sa_mask); allocated = posix_memalign((void**)&buf, getpagesize(), buffSize); if (0 != allocated) { perror("posix_memalign error"); exit(1); } sigaction(SIGHUP, &act, NULL); int fd = open("testfile", O_RDWR | O_DIRECT); //for (i = 0; i < 1; ++i) for (; { if (lseek(fd, 0, SEEK_SET) == -1) { printf("lseek failed: %s\n", strerror(errno)); } if (read(fd, buf, buffSize) != buffSize) { printf("read failed: %s\n", strerror(errno)); } } }
代码中注册了信号SIG_HUP的信号处理函数,收到信号的时候应该会进入该处理函数。使用了O_DIRECT方式直接从磁盘读,然后运行该程序。在另外一个终端发送信号
while true; do pkill -HUP read; done
观察read进程,发现read确实进入了信号处理函数(终端输出了"......")但是,程序并没有打印出“read failed”错误,这与我们的预期不太符合,测试发现调用write接口时,现象也一样。
为了进一步验证,我尝试去read终端设备,然后发信号,整个流程跟上面read测试基本相同,测试代码如下:
#include#include #include #include #include #include #include #include void int_handler(int signum) { printf("....\n"); } int main() { char buf[128]; ssize_t ret; struct sigaction oldact; struct sigaction act; act.sa_handler = int_handler; //act.sa_flags = SA_INTERRUPT; act.sa_flags = SA_RESTART; sigemptyset(&act.sa_mask); if(-1 == sigaction(SIGHUP, &act, &oldact)) { exit(1); } bzero(buf, 100); while(true) { ret = read(STDIN_FILENO, buf, 10); if(-1 == ret) { perror("read terminal"); //printf("read error%s\n"), strerror(errno); } } return 0; }
编译运行该函数,然后在另外一个终端为其发送信号:
while true; do pkill -HUP read; done