Why is there no record (2) returning an EINTR?

I read about EINTR on write(2) etc. and trying to determine if I need to check it in my program. As a test for performance, I tried to write a program that will work in it. Loop program forever by repeatedly repeating a file.

Then in a separate shell I run:

 while true; do pkill -HUP test; done 

However, the only conclusion I can see from test.c is this . from the signal handler. Why isn't SIGHUP calling write(2) called?

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)); } } } 
+4
source share
3 answers

Linux aims to avoid EINTR when writing to / reading from files; see discussion here . Despite the fact that the process blocks writing to the disk, it can be put into a sleep-free state (process code D ), which indicates that it cannot be interrupted at this time, It depends on the device driver; an online copy of Linux device drivers, 3rd edition is a good reference to how it looks on the kernel side.

You still need to handle the EINTR for other platforms that may not match, or for pipes and sockets where the EINTR can be defined.

Note that you only write sizeof(void *) bytes at a time:

 char* buf = malloc(1024*1024*128); if (write(fd, buf, sizeof(buf)) != sizeof(buf)) 

It should be

 const size_t BUF_SIZE = 1024*1024*128; char* buf = malloc(BUF_SIZE); if (write(fd, buf, BUF_SIZE) != BUF_SIZE) 
+8
source

There are 2 possibilities:

  • You write very few bytes since you are abusing the sizeof operator . Thus, write happens instantly and never breaks - you only write 4 or 8 bytes at a time

  • Somehow restarting syscall, as if you applied SA_RESTART to sigaction


In your code, since buf is a pointer, sizeof(buf) gives the size of the pointer on your computer, not the (much larger) allocated space

+5
source

If you check the man page for EINTR

The call was interrupted by a signal before recording any data

Also on page (7) of the manual :

read (2), readv (2), write (2), writev (2) and ioctl (2) cause "slow" devices. A β€œslow” device is a device in which an I / O call can block for an indefinite time, such as a terminal, pipe, or socket. (A drive is not a slow device according to this definition.) If an I / O call on a slow device already transferred some data by the time it is interrupted by the signal handler, then the call will return a success status (usually the number of bytes transferred).

Taking these two together when writing to a file on disk, and write began to write (even if only one byte was written), returning from this call to write will succeed.

0
source

All Articles