NAME

zkSelect - timed I/O

SYNOPSIS

#include "zkSysSelect.h"

int zkSelect(int nfds, fd_set* readfds, fd_set* writefds,
    fd_set* errorfds, struct timeval* timeout);
void FD_CLR(int fd, fd_set* fdset);
int FD_ISSET(int fd, fd_set* fdset);
void FD_SET(int fd, fd_set* fdset);
void FD_ZERO(fd_set* fdset);
int ZK_FD_MAXFD1(int fd);
int ZK_FD_MAXFDS(fd_set* readfds, fd_set* writefds,
    fd_set* errorfds);

DESCRIPTION

Important: the zkSelect() function has semantics that are quite different from the POSIX select() function. Please read this entire document before using zkSelect() in your code.

The zkSelect() function indicates if the specified socket descriptor is ready for reading or ready for writing. If the specified condition is false for the specified socket descriptor, zkSelect() blocks, up to the specified timeout interval, until the specified condition is true.

The zkSelect() function supports socket descriptors only. The behaviour of zkSelect() on file descriptors, or any other other kind of descriptor, is implementation-defined.

The nfds argument specifies the range of socket descriptors to be tested. It should be one greater than the highest-numbered socket descriptor set in readfds, writefds, and errorfds. This value can be calculated with the ZK_FD_MAXFD1() or ZK_FD_MAXFDS() functions.

The zkSelect() function tests the first nfds socket descriptors to have been passed to FD_SET() in each of readfds, writefds, and errorfds.

If the readfds argument is not NULL, it points to an object of type fd_set that on input specifies the socket descriptor to be checked for being ready to read, and on output indicates if the socket descriptor is ready to read. At most one socket descriptor may be set in the readfds argument.

If the writefds argument is not NULL, it points to an object of type fd_set that on input specifies the socket descriptor to be checked for being ready to write, and on output indicates if the socket descriptor is ready to write. At most one socket descriptor may be set in the writefds argument.

The errorfds argument must be NULL. It is present for compatibility with the POSIX select() function.

At most one of readfds and writefds may be non-NULL, and in the one that isn't NULL, at most one socket descriptor may be set. This means that zkSelect() may portably be used for timed I/O, but cannot portably be used for I/O multiplexing.

On successful completion, the objects pointed to by the readfds, writefds, and errorfds arguments are modified to indicate which socket descriptors are ready for reading, ready for writing, or have an error condition pending, respectively. For each socket descriptor less than nfds, the corresponding bit will be set on successful completion if it was set on input and the associated condition is true for that file descriptor.

If the timeout argument is not NULL, it points to an object of type struct timeval that specifies a maximum interval to wait for the selection to complete. If the timeout argument points to an object of type struct timeval whose members are 0, zkSelect() does not block. If the timeout argument is NULL, zkSelect() blocks until an event causes one of the masks to be returned with a valid (non-zero) value. If the time limit expires before any event occurs that would cause one of the masks to be set to a non-zero value, zkSelect() completes successfully and returns 0.

On successful completion, the object pointed to by the timeout argument may be modified.

Implementations may place limitations on the maximum timeout interval supported. Implementations may also place limitations on the granularity of timeout intervals. If the requested timeout interval requires a finer granularity than the implementation supports, the actual timeout interval will be rounded up to the next supported value.

If the readfds, writefds, and errorfds arguments are all NULL and the timeout argument is not NULL, zkSelect() blocks for the time specified, or until interrupted by a signal. If the readfds, writefds, and errorfds arguments are all NULL and the timeout argument is NULL, the behaviour is implementation-defined.

On failure, the objects pointed to by the readfds, writefds, and errorfds arguments are not modified. If the timeout interval expires without the specified condition being true for any of the specified file descriptors, the objects pointed to by the readfds, writefds, and errorfds arguments have all bits set to 0.

File descriptor masks of type fd_set can be initialised and tested with FD_CLR(), FD_ISSET(), FD_SET(), and FD_ZERO(). It is unspecified whether each of these is a macro or a function. If a macro definition is suppressed in order to access an actual function, or a program defines an external identifier with any of these names, the behaviour is undefined.

FD_CLR(fd, &fdset)
Clears the bit for the socket descriptor fd in the socket descriptor set fdset.
 
FD_ISSET(fd, &fdset)
Returns a non-zero value if the bit for the socket descriptor fd is set in the socket descriptor set pointed to by fdset, and 0 otherwise.
 
FD_SET(fd, &fdset)
Sets the bit for the socket descriptor fd in the socket descriptor set fdset.
 
FD_ZERO(&fdset)
Initialises the socket descriptor set fdset to have zero bits for all socket descriptors.

The behaviour of these macros is undefined if the fd argument is less than 0 or greater than or equal to FD_SETSIZE, or if any of the arguments are expressions with side effects.

The value to pass as the nfds argument to zkSelect() may be calculated by calling the ZK_FD_MAXFD1() or ZK_FD_MAXFDS() functions. It is unspecified whether each of these is a macro or a function. If a macro definition is suppressed in order to access an actual function, or a program defines an external identifier with any of these names, the behaviour is undefined.

ZK_FD_MAXFD1(fd)
Computes a value for nfds. This function is suitable for cases where zkSelect() is only passed a single socket descriptor in a single fd_set.
 
ZK_FD_MAXFDS(&readfds, &writefds, &exceptfds)
Computes a value for nfds. This function is suitable for cases where zkSelect() is passed more than one non-NULL fd_set, or when one or more fd_sets contain more than one socket descriptor.

RETURN VALUE

FD_CLR(), FD_SET() and FD_ZERO() return no value. FD_ISSET() returns a non-zero value if the bit for the socket descriptor fd is set in the socket descriptor set pointed to by fdset, and 0 otherwise.

ZK_FD_MAXFD1() and ZK_FD_MAXFDS() return a value that may be passed as the nfds argument to zkSelect().

On successful completion, zkSelect() returns the total number of bits set in the bit masks. Otherwise, -1 is returned, and errno is set to indicate the error.

ERRORS

Under the following conditions, zkSelect() fails and sets errno to:

[EBADF]
One or more of the socket descriptor sets specified a socket descriptor that is not a valid open socket descriptor.
[EINTR]
The zkSelect() function was interrupted before any of the selected events occurred and before the timeout interval expired. If SA_RESTART has been set for the interrupting signal, it is implementation-dependent whether zkSelect() restarts or returns with [EINTR].
[EINVAL]
An invalid timeout interval was specified.
[EINVAL]
The nfds argument is less than 0 or greater than FD_SETSIZE.
[EINVAL]
One of the specified file descriptors refers to a STREAM or multiplexer that is linked (directly or indirectly) downstream from a multiplexer.

PORTABILITY

On some systems, zkSelect() may support the following additional functionality:

The descriptors in each of readfds, writefds, and errorfds may refer to kinds of descriptors other than socket descriptors, such as file descriptors.
 
The function may support non-NULL values for readfds, writefds, and errorfds, in any combination.
 
The function may support setting more than one descriptor in any of readfds, writefds, and errorfds. This, combined with the preceding item, allows support for I/O multiplexing.

Obviously, reliance on such functionality reduces the portability of code.