A signal can arrive and be handled while an I/O primitive such as
open or read is waiting for an I/O device. If the signal
handler returns, the system faces the question: what should happen next?
POSIX specifies one approach: make the primitive fail right away. The
error code for this kind of failure is EINTR. This is flexible,
but usually inconvenient. Typically, POSIX applications that use signal
handlers must check for EINTR after each library function that
can return it, in order to try the call again. Often programmers forget
to check, which is a common source of error.
The GNU library provides a convenient way to retry a call after a
temporary failure, with the macro TEMP_FAILURE_RETRY:
— Macro: TEMP_FAILURE_RETRY (expression)
This macro evaluates expression once. If it fails and reports
error code EINTR, TEMP_FAILURE_RETRY evaluates it again,
and over and over until the result is not a temporary failure.
The value returned by TEMP_FAILURE_RETRY is whatever value
expression produced.
BSD avoids EINTR entirely and provides a more convenient
approach: to restart the interrupted primitive, instead of making it
fail. If you choose this approach, you need not be concerned with
EINTR.
You can choose either approach with the GNU library. If you use
sigaction to establish a signal handler, you can specify how that
handler should behave. If you specify the SA_RESTART flag,
return from that handler will resume a primitive; otherwise, return from
that handler will cause EINTR. See Flags for Sigaction.
Another way to specify the choice is with the siginterrupt
function. See BSD Handler.
When you don't specify with sigaction or siginterrupt what
a particular handler should do, it uses a default choice. The default
choice in the GNU library depends on the feature test macros you have
defined. If you define _BSD_SOURCE or _GNU_SOURCE before
calling signal, the default is to resume primitives; otherwise,
the default is to make them fail with EINTR. (The library
contains alternate versions of the signal function, and the
feature test macros determine which one you really call.) See Feature Test Macros.
The description of each primitive affected by this issue
lists EINTR among the error codes it can return.
There is one situation where resumption never happens no matter which
choice you make: when a data-transfer function such as read or
write is interrupted by a signal after transferring part of the
data. In this case, the function returns the number of bytes already
transferred, indicating partial success.
This might at first appear to cause unreliable behavior on
record-oriented devices (including datagram sockets; see Datagrams),
where splitting one read or write into two would read or
write two records. Actually, there is no problem, because interruption
after a partial transfer cannot happen on such devices; they always
transfer an entire record in one burst, with no waiting once data
transfer has started.
Published under the terms of the GNU General Public License