синхронное мультиплексирование ввода / вывода (synchronous I/O multiplexing)
Ошибки (баги) (Bugs)
POSIX allows an implementation to define an upper limit,
advertised via the constant FD_SETSIZE
, on the range of file
descriptors that can be specified in a file descriptor set. The
Linux kernel imposes no fixed limit, but the glibc implementation
makes fd_set a fixed-size type, with FD_SETSIZE
defined as 1024,
and the FD_*
() macros operating according to that limit. To
monitor file descriptors greater than 1023, use poll(2) or
epoll(7) instead.
The implementation of the fd_set arguments as value-result
arguments is a design error that is avoided in poll(2) and
epoll(7).
According to POSIX, select
() should check all specified file
descriptors in the three file descriptor sets, up to the limit
nfds-1. However, the current implementation ignores any file
descriptor in these sets that is greater than the maximum file
descriptor number that the process currently has open. According
to POSIX, any such file descriptor that is specified in one of
the sets should result in the error EBADF
.
Starting with version 2.1, glibc provided an emulation of
pselect
() that was implemented using sigprocmask(2) and select
().
This implementation remained vulnerable to the very race
condition that pselect
() was designed to prevent. Modern
versions of glibc use the (race-free) pselect
() system call on
kernels where it is provided.
On Linux, select
() may report a socket file descriptor as "ready
for reading", while nevertheless a subsequent read blocks. This
could for example happen when data has arrived but upon
examination has the wrong checksum and is discarded. There may
be other circumstances in which a file descriptor is spuriously
reported as ready. Thus it may be safer to use O_NONBLOCK
on
sockets that should not block.
On Linux, select
() also modifies timeout if the call is
interrupted by a signal handler (i.e., the EINTR
error return).
This is not permitted by POSIX.1. The Linux pselect
() system
call has the same behavior, but the glibc wrapper hides this
behavior by internally copying the timeout to a local variable
and passing that variable to the system call.