When to check for EINTR and repeat the function call?
Asked Answered
P

4

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?

Perforce answered 10/2, 2011 at 16:6 Comment(2)
why do you want to call your function a second time? after the interrupt was handled, control is handed back to your application/functionInsanitary
Similar question: #3634344Perforce
S
18

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.

Sparerib answered 10/2, 2011 at 16:49 Comment(10)
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?Perforce
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.Perforce
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.Perforce
@Perforce 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.Tweeter
@Perforce 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.Hughett
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 @Hughett 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, ...).Chunchung
@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.Sparerib
@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. :-)Hyperkeratosis
@R..GitHubSTOPHELPINGICE: Very good to know, thanks! It's still very much documented as relevant upstream <git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/…>. If you have any references, sending a quick patch or report would be super cool <kernel.org/doc/man-pages/contributing.html>.Hughett
Aged like milk news.ycombinator.com/item?id=25967594Unnumbered
C
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.

Circumvolution answered 10/2, 2011 at 16:20 Comment(0)
H
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.

Hyperkeratosis answered 17/1, 2020 at 22:33 Comment(13)
What makes select and poll special here? I'm seeing EINTR on other libc calls, namely waitpid.Resort
@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.Hyperkeratosis
What if you're using a library like ncurses, which messes itself with signals (ie it sets a SIGWINCH handler without SA_RESTART)?Creamy
@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.Hyperkeratosis
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.Duvall
@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".Hyperkeratosis
@R.. GitHub STOP HELPING ICE Where did you find this exact information EINTR error only happens when you have a custom signal handler?Duvall
@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). pubs.opengroup.org/onlinepubs/9699919799/functions/…Hyperkeratosis
@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".Duvall
@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.Hyperkeratosis
@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 knowDuvall
@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").Hyperkeratosis
@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 handlerDuvall
E
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);
}
Erect answered 12/2, 2013 at 9:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.