486 Chapter 23
23.3 Setting Timeouts on Blocking Operations
One use of real-time timers is to place an upper limit on the time for which a block-
ing system call can remain blocked. For example, we may wish to cancel a read()
from a terminal if the user has not entered a line of input within a certain time. We
can do this as follows:
- Call sigaction() to establish a handler for SIGALRM, omitting the SA_RESTART flag, so
that system calls are not restarted (refer to Section 21.5). - Call alarm() or setitimer() to establish a timer specifying the upper limit of time
for which we wish the system call to block. - Make the blocking system call.
- After the system call returns, call alarm() or setitimer() once more to disable the
timer (in case the system call completed before the timer expired). - Check to see whether the blocking system call failed with errno set to EINTR
(interrupted system call).
Listing 23-2 demonstrates this technique for read(), using alarm() to establish the
timer.
Listing 23-2: Performing a read() with timeout
–––––––––––––––––––––––––––––––––––––––––––––––––––––– timers/timed_read.c
#include <signal.h>
#include "tlpi_hdr.h"
#define BUF_SIZE 200
static void /* SIGALRM handler: interrupts blocked system call */
handler(int sig)
{
printf("Caught signal\n"); /* UNSAFE (see Section 21.1.2) */
}
int
main(int argc, char *argv[])
{
struct sigaction sa;
char buf[BUF_SIZE];
ssize_t numRead;
int savedErrno;
if (argc > 1 && strcmp(argv[1], "--help") == 0)
usageErr("%s [num-secs [restart-flag]]\n", argv[0]);
/* Set up handler for SIGALRM. Allow system calls to be interrupted,
unless second command-line argument was supplied. */
sa.sa_flags = (argc > 2)? SA_RESTART : 0;
sigemptyset(&sa.sa_mask);