Interrupted Primitives (The GNU C Library) (original) (raw)


24.5 Primitives Interrupted by Signals

A signal can arrive and be handled while an I/O primitive such asopen 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 C 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, and examines its value as type long int. If the value equals -1, that indicates a failure and errno should be set to show what kind of failure. 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 valueexpression 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 withEINTR.

You can choose either approach with the GNU C Library. If you usesigaction 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 siginterruptfunction. See BSD Signal Handling.

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 C Library is to make primitives fail with EINTR.

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 orwrite 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 Datagram Socket Operations), 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.