Node:Waiting for I/O, Next:Synchronizing I/O, Previous:Memory-mapped I/O, Up:Low-Level I/O
Sometimes a program needs to accept input on multiple input channels whenever input arrives. For example, some workstations may have devices such as a digitizing tablet, function button box, or dial box that are connected via normal asynchronous serial interfaces; good user interface style requires responding immediately to input on any device. Another example is a program that acts as a server to several other processes via pipes or sockets.
You cannot normally use read
for this purpose, because this
blocks the program until input is available on one particular file
descriptor; input on other channels won't wake it up. You could set
nonblocking mode and poll each file descriptor in turn, but this is very
inefficient.
A better solution is to use the select
function. This blocks the
program until input or output is ready on a specified set of file
descriptors, or until a timer expires, whichever comes first. This
facility is declared in the header file sys/types.h
.
In the case of a server socket (see Listening), we say that
"input" is available when there are pending connections that could be
accepted (see Accepting Connections). accept
for server
sockets blocks and interacts with select
just as read
does
for normal input.
The file descriptor sets for the select
function are specified
as fd_set
objects. Here is the description of the data type
and some macros for manipulating these objects.
fd_set | Data Type |
The fd_set data type represents file descriptor sets for the
select function. It is actually a bit array.
|
int FD_SETSIZE | Macro |
The value of this macro is the maximum number of file descriptors that a
fd_set object can hold information about. On systems with a
fixed maximum number, FD_SETSIZE is at least that number. On
some systems, including GNU, there is no absolute limit on the number of
descriptors open, but this macro still has a constant value which
controls the number of bits in an fd_set ; if you get a file
descriptor with a value as high as FD_SETSIZE , you cannot put
that descriptor into an fd_set .
|
void FD_ZERO (fd_set *set) | Macro |
This macro initializes the file descriptor set set to be the empty set. |
void FD_SET (int filedes, fd_set *set) | Macro |
This macro adds filedes to the file descriptor set set. |
void FD_CLR (int filedes, fd_set *set) | Macro |
This macro removes filedes from the file descriptor set set. |
int FD_ISSET (int filedes, fd_set *set) | Macro |
This macro returns a nonzero value (true) if filedes is a member of the file descriptor set set, and zero (false) otherwise. |
Next, here is the description of the select
function itself.
int select (int nfds, fd_set *read-fds, fd_set *write-fds, fd_set *except-fds, struct timeval *timeout) | Function |
The select function blocks the calling process until there is
activity on any of the specified sets of file descriptors, or until the
timeout period has expired.
The file descriptors specified by the read-fds argument are checked to see if they are ready for reading; the write-fds file descriptors are checked to see if they are ready for writing; and the except-fds file descriptors are checked for exceptional conditions. You can pass a null pointer for any of these arguments if you are not interested in checking for that kind of condition. A file descriptor is considered ready for reading if it is not at end of
file. A server socket is considered ready for reading if there is a
pending connection which can be accepted with "Exceptional conditions" does not mean errors--errors are reported immediately when an erroneous system call is executed, and do not constitute a state of the descriptor. Rather, they include conditions such as the presence of an urgent message on a socket. (See Sockets, for information on urgent messages.) The The timeout specifies the maximum time to wait. If you pass a
null pointer for this argument, it means to block indefinitely until one
of the file descriptors is ready. Otherwise, you should provide the
time in The normal return value from If Any signal will cause If an error occurs,
|
Portability Note: The select
function is a BSD Unix
feature.
Here is an example showing how you can use select
to establish a
timeout period for reading from a file descriptor. The input_timeout
function blocks the calling process until input is available on the
file descriptor, or until the timeout period expires.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
int
input_timeout (int filedes, unsigned int seconds)
{
fd_set set;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
/* select
returns 0 if timeout, 1 if input available, -1 if error. */
return TEMP_FAILURE_RETRY (select (FD_SETSIZE,
&set, NULL, NULL,
&timeout));
}
int
main (void)
{
fprintf (stderr, "select returned %d.\n",
input_timeout (STDIN_FILENO, 5));
return 0;
}
There is another example showing the use of select
to multiplex
input from multiple sockets in Server Example.