Applying the EINTR Error Code

Except when the sigsuspend(2) technique is used, a signal can be caught by a signal handler at any time. This restricts the choice of available functions to those that are re-entrant. Consequently, when non–re-entrant functions must be called, a different technique must be used.

A signal handler can post a result to a global flag variable, which is later polled by the application. Using this technique, no re-entrancy issues arise because the event is synchronous (polled) instead of being asynchronous. The following example shows a signal handler that posts a true result to the flag variable gotSIGINT:

static int gotSIGINT = 0;   /* True when SIGINT arrives */

static void
catch_SIGINT(int signo) {
    gotSIGINT = 1;          /* Post the flag */
}

This part of the application is simple, and no re-entrancy issues arise. The difficulty is that, when the program is blocked waiting for a system call to complete, it never gets a chance to poll for the posted SIGINT event. The following statement illustrates another part of the program that will wait indefinitely until data arrives on standard input:

int z;
char buf[256];

z = read(0,buf,sizeof buf);   /* Obtain terminal input */

When the program is waiting for input, the signal handler can still post its event by assigning 1 to variable gotSIGINT. However, the application cannot break out of the read(2) function to test if the event occurred. Instead, the application will wait indefinitely until all of the data arrives or an end-of-file is received.

To avoid this difficulty, the designers of UNIX offered the following solution: When a signal handler returns, certain system calls immediately return the error code EINTR. This allows the calling application to regain control from its blocked state and have a chance to poll for any events that may have been posted by a signal handler.

The value of the variable gotSIGINT can be tested in the example given earlier. If no event was detected by the calling application, it can simply ignore the error and retry the system call. The following illustrates this procedure in code:

int z;
char buf[256];
do  {
    z = read(0,buf,sizeof buf);         /* Obtain terminal input */
    if ( gotSIGINT )                    /* Was SIGINT posted? */
        process_SIGINT();               /* Yes, Process the SIGINT event */
} while ( z == -1 && errno == EINTR );  /* Repeat while EINTR */

This loop is typical of many that process the EINTR error code. The system call read(2) is attempted, which may block indefinitely (for terminal input). If an error occurs, the code tests to see if SIGINT was posted by looking at global variable gotSIGINT. If gotSIGINT is true, then function process_SIGINT() will perform the actions that the signal handler was unable to perform. The loop repeats at the while clause as long as an error is reported by z and the error code in errno is equal to EINTR.

Note

EINTR—Interrupted system call This error is returned by a number of system calls to indicate that a signal handler was executed as a result of receiving a signal. This is done to permit the calling application to become unblocked by a blocking system call, so that action may be executed for a received signal.


Many people in various UNIX Usenet newsgroups have complained about this behavior over the years. However, this behavior is a feature of the operating system and is not a defect. You should get into the habit of thinking about blocking system calls when you write applications.

If a function might block the execution of your program for a long time, then you may have to be concerned with EINTR processing loops. The general rule is if the system call may block for long or indefinite periods, then EINTR is possible. Note for example that read(2) will not return EINTR for file reads, since this type of call is not considered long. However, when read(2) is used to read terminal input or a socket, the error EINTR can be returned.

Always check the man(1) pages of system calls to see if EINTR is possible. If your code must be portable, be sure to check the man(1) pages of the other platforms as well. Some platforms, particularly SGI's IRIX 6.5, will return EINTR when the others do not.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.23.127.197