我一直在阅读EINTR
等write(2)
,并试图确定是否需要在我的程序中检查它。作为一个完整性检查,我试图写一个会遇到它的程序。程序永远循环,重复写入文件。
然后,在一个单独的shell中,我运行:
while true; do pkill -HUP test; done
但是,我从test.c看到的唯一输出是来自信号处理程序的.
。为什么SIGHUP
导致write(2)
失败?
test.c的:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
void hup_handler(int sig)
{
printf(".");
fflush(stdout);
}
int main()
{
struct sigaction act;
act.sa_handler = hup_handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGHUP, &act, NULL);
int fd = open("testfile", O_WRONLY);
char* buf = malloc(1024*1024*128);
for (;;)
{
if (lseek(fd, 0, SEEK_SET) == -1)
{
printf("lseek failed: %s\n", strerror(errno));
}
if (write(fd, buf, sizeof(buf)) != sizeof(buf))
{
printf("write failed: %s\n", strerror(errno));
}
}
}
答案 0 :(得分:8)
Linux往往会避免EINTR
对文件的写入/读取;见discussion here。虽然进程在磁盘写入时阻塞,但它可能处于uninterruptible sleep状态(进程代码D
),表示当时不能中断。这取决于设备驱动程序; online copy of Linux Device Drivers, 3rd Edition对于内核方面的显示方式是一个很好的参考。
您仍然需要为可能不相同的其他平台处理EINTR,或者对于绝对可能发生EINTR的管道和插槽处理EINTR。
请注意,您一次只能写sizeof(void *)
个字节:
char* buf = malloc(1024*1024*128);
if (write(fd, buf, sizeof(buf)) != sizeof(buf))
这应该是
const size_t BUF_SIZE = 1024*1024*128;
char* buf = malloc(BUF_SIZE);
if (write(fd, buf, BUF_SIZE) != BUF_SIZE)
答案 1 :(得分:5)
有两种可能性:
您写的字节很少,因为您滥用了sizeof
运算符。因此write
瞬间发生,它永远不会被打断 - 你一次只写4或8个字节
系统调用以某种方式重新启动,就像您将SA_RESTART
应用于sigaction
在你的代码中,由于buf
是指针,sizeof(buf)
会产生机器上指针的大小,而不是(更大)分配的空间
答案 2 :(得分:1)
如果您查看EINTR
的{{3}}
在写入任何数据之前,呼叫被信号中断
同样来自manual page:
读取(2),readv(2),write(2),writev(2)和ioctl(2)调用“慢”设备。 “慢”设备是I / O调用可能无限期阻塞的设备,例如终端,管道或套接字。 (根据此定义,磁盘不是慢速设备。)如果慢速设备上的I / O调用在信号处理程序中断时已经传输了某些数据,则该调用将返回成功状态(通常,传输的字节数。)
将这两者放在一起,如果写入磁盘上的文件,并且write
已经开始写入(即使只写了一个字节),那么write
调用的返回将是成功。