Watching Standard Input for Data in C
This post describes a recipe written in C around the select() function to wait for data on stdin, eventually timing out if it takes too long to arrive.
1 In a Nutshell
The way to go is to use the select()
function. In this example we want to have select()
repeatedly keep a watch on stdin
and see if there's something to nibble, in which case it will be given to read()
. If a timeout is reached, report it and bail out. Do the same if an error occurs.
2 Code
Headers – According to the man page,
select()
is declared insys/select.h
but it works without including it. And the man page example doesn't include it either. (It seems to be included insys/time.h
).#include <sys/time.h> /* timeval */
File descriptors – The
select()
function works on sets of file descriptors. A set should be cleared with theFD_ZERO
macro before you can add new descriptors to it with theFD_SET
macro:Here, we only addfd_set fds; FD_ZERO(&fds); FD_SET(0, &fds);
stdin
(0
) to the set.Timeouts – Use a
struct timeval
to set the timeout:struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0;
Repeatedly read stdin – Have
select()
keep a weather eye out and callread()
when there's something sensible to read:while (1) { retval = select(1, &fds, NULL, NULL, &tv); if (retval == -1) { perror("select"); return 1; } else if (retval == 0) { printf("timeout\n"); return 1; } else { printf("ok\n"); read(0, &buf, 1); } }
- The first argument is the highest-numbered file descriptor of all three sets
+ 1
. Apparently you're better off setting it toFD_SETSIZE
. The two next arguments, here set toNULL
, are respectively writing and exception sets. The last argument is thetimeval
. - If the value returned by
select()
is-1
, something went wrong anderrno
is set. If the return value is0
, the timeout has been reached. This is not considered an error, mind you. In any other case, something came up to read. You then have to callread()
, otherwiseselect()
will pass again immediately for the same reason. See it as a queue whereselect()
chirps cheerfully when there's something to read and will keep doing so as long asread()
hasn't read all there's to read in the queue. - There's one funny thing with the Linux implementation of
select()
: thetimeval
is altered so that the next timeout is as short as the previousselect()
had to wait. So if you want the timeout to always be the same, give its value after each call toselect()
.
- The first argument is the highest-numbered file descriptor of all three sets