44

I am programming a user application for a embedded Linux system, and I am using the common functions such as open, close, read, ioctl, etc. for the devices. Now, I read about EINTR, indicates that the function was interrupted by a signal, but I am not sure about the implications. In all the example programs I have, sometimes it is done, e.g. ioctl(), sometimes it is not done, e.g. read(). So, I am a little bit confused.

When do I preferably check for EINTR and repeat the function call?

hochl
  • 12,524
  • 10
  • 53
  • 87
stefangachter
  • 845
  • 2
  • 10
  • 16
  • why do you want to call your function a second time? after the interrupt was handled, control is handed back to your application/function – knittl Feb 10 '11 at 16:14
  • Similar question: http://stackoverflow.com/questions/3633844/question-on-signal-handling-interrupt-handling – stefangachter Feb 11 '11 at 06:44

4 Answers4

17

See sigaction : http://pubs.opengroup.org/onlinepubs/009695399/functions/sigaction.html

SA_RESTART
  This flag affects the behavior of interruptible functions; that is, those 
  specified to fail with errno set to EINTR. If set, and a function specified 
  as interruptible is interrupted by this signal, the function shall restart 
  and shall not fail with EINTR unless otherwise specified. If the flag is not 
  set, interruptible functions interrupted by this signal shall fail with errno 
  set to EINTR.

By default, you have the SA_RESTART behavior, so you don't have to worry about EINTR, if you don't play with signals.

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
Yann Droneaud
  • 5,277
  • 1
  • 23
  • 39
  • 1
    So, as long as I don't use signals in my user applications, I don't have to worry about EINTR? But e.g. read() is a system call, therefore isn't it possible that read() could be interrupted by signal? – stefangachter Feb 11 '11 at 06:24
  • 3
    After spending some more time reading I came to the conclusion that I have to check for interrupted systems calls, which are not taken into account by SA_RESTART flag. – stefangachter Feb 11 '11 at 07:23
  • After all, this is only of importance inside a signal handler. As long as I don't have a signal handler, I have not care about. – stefangachter Feb 11 '11 at 07:32
  • 6
    @stefangachter As you concluded, It's important to notice that SA_RESTART does not always apply. Some interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler. Check [Signal man page for details](http://man7.org/linux/man-pages/man7/signal.7.html). – kikeenrique Sep 20 '13 at 08:35
  • 4
    @stefangachter Actually sometimes you do. *"On Linux, even in the absence of signal handlers, certain blocking interfaces can fail with the error EINTR after the process is stopped by one of the stop signals and then resumed via SIGCONT. This behavior is not sanctioned by POSIX.1, and doesn't occur on other systems."* As kikeenrique pointed out, see `signal(7)` for definitive Linux-specific info. – tne Mar 31 '15 at 18:13
  • How can I make sure, that there is really no signal handler setup in my progam? Libraries, that I include in my program could set up signal handlers or is that not usual? If I only set up my own signal handlers with activated SA_RESTART and if I do not care about the problem mentioned above by @tne concerning SIGCONT: Should I still wrap my blocking calls in a loop and check for EINTR? It gets pretty ugly, if you have many of them (accept, read, write, ...). – Niklas Peter Feb 15 '16 at 14:37
  • @NiklasPeter libraries *must not* set signal handlers without notice, or it's doomed to break anytime soon. A library should cooperate with the program it's linked with and with any other libraries. It's usualy incompatible with usage of signals. – Yann Droneaud Feb 16 '16 at 19:26
  • @tne: That behavior was a bug on Linux that was fixed over a decade ago (before your comment), so by now it should not be relevant at all. :-) – R.. GitHub STOP HELPING ICE Jan 17 '20 at 22:26
  • @R..GitHubSTOPHELPINGICE: Very good to know, thanks! It's still very much documented as relevant upstream . If you have any references, sending a quick patch or report would be super cool . – tne Jan 18 '20 at 10:57
  • Aged like milk https://news.ycombinator.com/item?id=25967594 – nurgasemetey Jan 30 '21 at 13:19
4

Is your application event driven? (Meaning its main loop include select()/epoll_wait() call).

In an event driven application you can block all signals and only unblock them for the duration of pselect()/epoll_pwait() call. This way the rest of your code never have to deal with EINTR.

Shmil The Cat
  • 4,548
  • 2
  • 28
  • 37
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
4

I know this question is old but I think there's more to be said. To answer the specific question in the title: basically, never.

Aside from select and poll, EINTR can only happen if you've installed (either by mistake/not understanding how to use sigaction, or because you want to be able to interrupt blocking operations) interrupting signal handlers. Looping to retry when a function fails with EINTR just undoes that. Doing so is an old anti-pattern from the 80s and early to mid 90s when lots of operating systems were buggy and reportedly generated EINTR under non-conforming circumstances, but these bugs are long gone.

It is possible that, even in an application where you want to be able to interrupt things with signals, there is some code whose successful completion is so important that you can't treat EINTR as an error condition and return back to the caller without completing the operation. In such a circumstance, it might make sense to install a retry loop, but it's probably better to mask signals (at least the potentially-interrupting ones) during the operation and unmasks after it finishes.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • What makes `select` and `poll` special here? I'm seeing `EINTR` on other libc calls, namely `waitpid`. – Max Jan 22 '20 at 22:25
  • 1
    @Max: For most functions, `EINTR` is only specified for "The function was interrupted by a signal" or similar, where *interrupted* is defined only to happen for non-`SA_RESTART` signal handlers. For `poll`, however, it's defined as "A signal was caught during poll()", independent of whether that signal was an interrupting one. – R.. GitHub STOP HELPING ICE Jan 23 '20 at 00:37
  • What if you're using a library like ncurses, which messes itself with signals (ie it sets a SIGWINCH handler without SA_RESTART)? –  Feb 09 '20 at 19:37
  • 1
    @mosvy: Then you either don't use the buggy library, you report the bug and get it fixed and only support fixed versions, or you hack around it (e.g. fix it up after the library sets it wrong, or feed it a wrapped `sigaction` that ignores the malicious flags the buggy library set). Note: libraries should not be setting signal handlers to begin with but should allow the caller to set them *if it wants to*. – R.. GitHub STOP HELPING ICE Feb 09 '20 at 21:32
  • In theory, EINTR can occur even if you don't set any signal handlers. So it's a good practice to check for EINTR just to be safe. – Heil Programmierung Mar 01 '23 at 14:32
  • @HeilProgrammierung: What theory is this you're going by? There is no allowance in the specification for standard error codes (already assigned a meaning for the interface) to be generated for conditions other than the ones they're specified for, unless the spec explicitly says something like "or other implementation-defined conditions". – R.. GitHub STOP HELPING ICE Mar 01 '23 at 18:30
  • @R.. GitHub STOP HELPING ICE Where did you find this exact information EINTR error only happens when you have a custom signal handler? – Heil Programmierung Mar 01 '23 at 18:59
  • @HeilProgrammierung: It's spread out across multiple places. Mainly 2.3 ¶7, the clauses of 2.4.3 containing "shall have no effect on the process", and the specifications of individual functions that block and can fail with `EINTR` (their normative text under ERRORS headings). https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html – R.. GitHub STOP HELPING ICE Mar 01 '23 at 19:19
  • @R.. GitHub STOP HELPING ICE Prior to that it states "If the default action is to ignore the signal....shall have not effect on the process". What if it's not "ignore"? For functions like accept, read, write it just says "The function call was interrupted by a signal". – Heil Programmierung Mar 01 '23 at 22:22
  • @HeilProgrammierung: The other default action is to terminate the process, in which case you don't have any question about seeing `EINTR` because the process no longer exists. – R.. GitHub STOP HELPING ICE Mar 02 '23 at 14:14
  • @R.. GitHub STOP HELPING ICE So a signal is either ignored, or kills a process, or acts according to your custom handler? That's a good thing to know – Heil Programmierung Mar 02 '23 at 14:45
  • @HeilProgrammierung: Sorry, there's also stopping/continuing the process I forgot to mention as possible default actions. Also very relevant that I forgot to cite is 2.4.4 Signal Effects on Other Functions, where the term "interrupted" is defined (relevant to when `EINTR` can happen if the spec says "the function call was interrupted by a signal"). – R.. GitHub STOP HELPING ICE Mar 02 '23 at 15:55
  • @R.. GitHub STOP HELPING ICE So even in the case of stopping/continuing signals, a function should be restarted? "...the original function shall continue at the point the process was stopped...." And EINTR will happen only if you specify your custom handler – Heil Programmierung Mar 02 '23 at 16:28
2

I had a similar problem when waiting for input from a named pipe with read().

I found an explanation and a useful macro for primitives in GNU libc documentation: TEMP_FAILURE_RETRY

Example:

TEMP_FAILURE_RETRY (read_return = read((int)example_fifo, buffer, (size_t)n));
if (read_return==-1){
    fprintf(stderr, "reader.c: read_fifo: read(): %s \n", strerror(errno));
    fflush(stderr);
}
lobosch
  • 21
  • 2