I've been reading about EINTR
on write(2)
etc, and trying to determine whether I need to check for it in my program. As a sanity check, I tried to write a program that would run into it. The program loops forever, writing repeatedly to a file.
Then, in a separate shell, I run:
while true; do pkill -HUP test; done
However, the only output I see from test.c is the .
s from the signal handler. Why isn't the SIGHUP
causing write(2)
to fail?
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));
}
}
}
Linux tends to avoid EINTR
on writes to/reads from files; see discussion here. While a process is blocking on a disk write, it may be placed in an uninterruptible sleep state (process code D
) which indicates that it cannot be interrupted at that time. This depends on the device driver; the online copy of Linux Device Drivers, 3rd Edition is a good reference for how this appears from the kernel side.
You still need to handle EINTR for other platforms which may not behave the same, or for pipes and sockets where EINTR definitely can occur.
Note that you're only writing sizeof(void *)
bytes at a time:
char* buf = malloc(1024*1024*128);
if (write(fd, buf, sizeof(buf)) != sizeof(buf))
This should be
const size_t BUF_SIZE = 1024*1024*128;
char* buf = malloc(BUF_SIZE);
if (write(fd, buf, BUF_SIZE) != BUF_SIZE)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With