| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
I have to monitor more than one (fd/connection/stream) at a time. How do I manage all of them?
Use select() or poll().
Note: select() was introduced in BSD, whereas poll() is an
artifact of SysV STREAMS. As such, there are portability issues; pure
BSD systems may still lack poll(), whereas some older SVR3
systems may not have select(). SVR4 added select(), and
the Posix.1g standard defines both.
select() and poll() essentially do the same thing, just
differently. Both of them examine a set of file descriptors to see if
specific events are pending on any, and then optionally wait for a
specified time for an event to happen.
[Important note: neither select() nor poll() do anything
useful when applied to plain files; they are useful for sockets, pipes,
ptys, ttys & possibly other character devices, but this is
system-dependent.]
There the similarity ends....
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The interface to select() is primarily based on the concept of an
fd_set, which is a set of FDs (usually implemented as a
bit-vector). In times past, it was common to assume that FDs were
smaller than 32, and just use an int to store the set, but these days,
one usually has more FDs available, so it is important to use the
standard macros for manipulating fd_sets:
fd_set set; FD_ZERO(&set); /* empties the set */ FD_SET(fd,&set); /* adds FD to the set */ FD_CLR(fd,&set); /* removes FD from the set */ FD_ISSET(fd,&set) /* true if FD is in the set */ |
In most cases, it is the system's responsibility to ensure that fdsets
can handle the whole range of file descriptors, but in some cases you
may have to predefine the FD_SETSIZE macro.
This is system-dependent;
check your select() manpage. Also, some systems have problems
handling more than 1024 file descriptors in select().
The basic interface to select is simple:
int select(int nfds, fd_set *readset,
fd_set *writeset,
fd_set *exceptset, struct timeval *timeout);
|
where
nfds the number of FDs to examine; this must be greater than the largest FD in any of the fdsets, not the actual number of FDs specified
readsetthe set of FDs to examine for readability
writesetthe set of FDs to examine for writability
exceptfdsthe set of FDs to examine for exceptional status (note: errors are not exceptional statuses)
timeoutNULL for infinite timeout, or points to a timeval specifying the maximum
wait time (if tv_sec and tv_usec both equal zero, then the
status of the FDs is polled, but the call never blocks)
The call returns the number of `ready' FDs found, and the three fdsets
are modified in-place, with only the ready FDs left in the sets. Use the
FD_ISSET macro to test the returned sets.
Here's a simple example of testing a single FD for readability:
int isready(int fd)
{
int rc;
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(fd,&fds);
tv.tv_sec = tv.tv_usec = 0;
rc = select(fd+1, &fds, NULL, NULL, &tv);
if (rc < 0)
return -1;
return FD_ISSET(fd,&fds) ? 1 : 0;
}
|
Note that we can pass NULL for fdsets that we aren't interested
in testing.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
poll() accepts a pointer to a list of struct pollfd, in
which the descriptors and the events you wish to poll for are stored.
The events are specified via a bitwise mask in the events field of the
structure. The instance of the structure will later be filled in and
returned to you with any events which occured. Macros defined by
‘poll.h’ on SVR4 (probably older versions as well), are used to
specify the events in the field. A timeout may be specified in
milliseconds, only the type provided is an integer which is quite
perplexing. A timeout of 0 causes poll() to return immediately;
a value of -1 will suspend poll until an event is found to be
true.
struct pollfd {
int fd; /* The descriptor. */
short events; /* The event(s) is/are specified here. */
short revents; /* Events found are returned here. */
};
|
A lot like select(), the return value if positive reflects how
many descriptors were found to satisfy the events requested. A zero
return value is returned if the timeout period is reached before any of
the events specified have occured. A negative value should immediately
be followed by a check of errno, since it signifies an error.
If no events are found, revents is cleared, so there's no need
for you to do this yourself.
The returned events are tested to contain the event.
Here's an example:
/* Poll on two descriptors for Normal data, or High priority data.
If any found call function handle() with appropriate descriptor
and priority. Don't timeout, only give up if error, or one of the
descriptors hangs up. */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stropts.h>
#include <poll.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define NORMAL_DATA 1
#define HIPRI_DATA 2
int poll_two_normal(int fd1,int fd2)
{
struct pollfd poll_list[2];
int retval;
poll_list[0].fd = fd1;
poll_list[1].fd = fd2;
poll_list[0].events = POLLIN|POLLPRI;
poll_list[1].events = POLLIN|POLLPRI;
while(1)
{
retval = poll(poll_list,(unsigned long)2,-1);
/* Retval will always be greater than 0 or -1 in this case.
Since we're doing it while blocking */
if(retval < 0)
{
fprintf(stderr,"Error while polling: %s\n",strerror(errno));
return -1;
}
if(((poll_list[0].revents&POLLHUP) == POLLHUP) ||
((poll_list[0].revents&POLLERR) == POLLERR) ||
((poll_list[0].revents&POLLNVAL) == POLLNVAL) ||
((poll_list[1].revents&POLLHUP) == POLLHUP) ||
((poll_list[1].revents&POLLERR) == POLLERR) ||
((poll_list[1].revents&POLLNVAL) == POLLNVAL))
return 0;
if((poll_list[0].revents&POLLIN) == POLLIN)
handle(poll_list[0].fd,NORMAL_DATA);
if((poll_list[0].revents&POLLPRI) == POLLPRI)
handle(poll_list[0].fd,HIPRI_DATA);
if((poll_list[1].revents&POLLIN) == POLLIN)
handle(poll_list[1].fd,NORMAL_DATA);
if((poll_list[1].revents&POLLPRI) == POLLPRI)
handle(poll_list[1].fd,HIPRI_DATA);
}
}
|
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
No. (Except on AIX, which has an incredibly ugly kluge to allow this.)
In general, trying to combine the use of select() or
poll() with using SysV message queues is troublesome. SysV IPC
objects are not handled by file descriptors, so they can't be passed to
select() or poll(). There are a number of workarounds, of
varying degrees of ugliness:
fork(), and have the child process handle the SysV IPC,
communicating with the parent process by a pipe or socket, which the
parent process can select() on.
select(), and
communicate with the parent by message queue.
(Other methods exist.)
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated on September, 10 2007 using texi2html 1.77.