4 ms·
I just tested it on macOS and Linux with the two main sources of EINTR: signal handlers and attaching a debugger. I tested by interrupting a read from stdin, b
by comex 6y ago
I just tested it on macOS and Linux with the two main sources of EINTR: signal handlers and attaching a debugger. I tested by interrupting a read from stdin, but the behavior for disk reads and writes should be similar.
Signal handlers: POSIX specifies that, after a process runs a signal handler which was triggered when it was in the middle of a system call, either the system call will automatically be resumed or it will fail with EINTR, depending on a per-signal-handler setting. If the signal handler was set with sigaction(), this setting is the SA_RESTART flag; otherwise it can be set by siginterrupt(), but the default seems to be implementation-defined(?). Anyway, it seems that both macOS and Linux enable restarting by default. (But well-written library code should take into account the possibility that something else in the process could have decided to disable it.)
Attaching a debugger (using ptrace): This interrupts system calls because the debugger expects to see a userland state. On Linux it seems to automatically restart the system call, but on macOS it produces EINTR. This behavior doesn't seem to be configurable on either OS.
On both OSes, when EINTR does occur in read(), fread() does not cover up for it by automatically retrying, regardless of whether it successfully read any bytes beforehand.
- saagarjha 6y agoWhich libc were you using on Linux, or were you making raw system calls? Because I think glibc’s behavior is to EINTR unless you define _GNU_SOURCE, which seems to me to be incompatible with your description…
- comex 6y agoglibc, Debian package version 2.31-3, without any special defines. Here is the program I used: https://gist.github.com/comex/58ba394588478bb1d506a998850b9436 https://gist.github.com/comex/58ba394588478bb1d506a998850b94... If I run the program and press Ctrl-C, it prints "interrupted" but then keeps going. However, if I add `siginterrupt(SIGINT, 1)` after the call to signal(), interrupting the read() produces EINTR as expected. Interestingly, the glibc manual used to state that the default behavior depended on the presence of _BSD_SOURCE or _GNU_SOURCE, but in 2014 it was changed to state that the default is always to use EINTR: https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=manual/signal.texi;h=51f68b5d3ec59ea8a662c18360a3ba15cebe80ef;hp=f0e57ddbe41af3b0948d64c1dea420c6b1db9928;hb=c941736c92fa3a319221f65f6755659b2a5e0a20;hpb=e8d8d7ec98af7c3777fd664adca8be5630afbc90 https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=manual/...
- saagarjha 6y agoOh, huh, that’s really interesting! I didn’t realize that glibc had changed their behavior; I wonder if this broke any applications…