linux-sysprog · intermediate · ~10 min

Time-out a blocking read with alarm()

Use alarm() + SIGALRM to bound a read.

Challenge

Put a time budget on a blocking read using alarm(): if no data arrives within the deadline, the read is interrupted and reported as a timeout.

Task

Implement int read_with_timeout(int fd, char *buf, int cap, int seconds) that reads from fd but gives up after seconds.

Input

  • fd: the file descriptor to read from.
  • buf, cap: destination buffer and its capacity.
  • seconds: the timeout in seconds.

Output

Installs a SIGALRM handler (so the alarm doesn't terminate the process), arms alarm(seconds), performs one read(fd, buf, cap), then cancels the alarm with alarm(0). Returns the number of bytes read on success, or -1 if the read was interrupted by the alarm (i.e. errno == EINTR).

Example

read_with_timeout(pipe_with_data, buf, 16, 3)   ->   2   (data was ready, e.g. "hi")
read_with_timeout(empty_pipe, buf, 16, 1)       ->   -1  (timed out after ~1s)

Edge cases

  • Data already available returns the byte count before the timeout fires.
  • An empty/blocked source returns -1 once the alarm interrupts the read.

Rules

  • The SIGALRM handler must NOT use SA_RESTART — you want the read to return EINTR.
  • Cancel the alarm with alarm(0) after the read.

Why this matters

alarm() + a no-op handler is the simplest way to put a time budget on a blocking syscall.

Input format

A file descriptor fd, a buffer buf of capacity cap, and a timeout in seconds.

Output format

The number of bytes read on success, or -1 if the read was interrupted by the alarm (errno == EINTR).

Constraints

Install a SIGALRM handler without SA_RESTART, arm alarm(seconds), read once, then alarm(0).

Starter code

#include <signal.h>
#include <unistd.h>
#include <errno.h>
int read_with_timeout(int fd, char *buf, int cap, int seconds) {
    /* TODO */
    return -1;
}

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.