Manpages

НАЗВАНИЕ

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO − синхронное мультиплексирование ввода-вывода

КРАТКАЯ СВОДКА

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, sigset_t * sigmask);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int
fd, fd_set *set);
FD_SET(int
fd, fd_set *set);
FD_ZERO(fd_set *
set);

ОПИСАНИЕ

Функции select и pselect ждут изменения статуса нескольких файловых дескрипторов.

Они почти идентичны, только

(i)

select использует тайм-аут в виде struct timeval (с секундами и микросекундами), тогда как pselect использует struct timespec (с секундами и наносекундами).

(ii)

Функция select может обновить параметр timeout, чтобы сообщить, сколько времени осталось. Функция pselect не изменяет этот параметр.

(iii)

Функция select не содержит параметра sigmask, и ведет себя как pselect с параметром sigmask, равным NULL.

Отслеживаются три независимых набора дескрипторов. Те, что перечислены в параметре readfds, будут отслеживаться на предмет появления новых символов, доступных для чтения (говоря точнее, операция чтения не будет блокирована -- в частности, файловый дескриптор находится в конце файла); те, что указаны в параметре writefds, будут отслеживаться на предмет того, что операция записи не будет заблокирована; те же, что указаны в параметре exceptfds, будут отслеживаться на предмет исключительных ситуаций. При возврате из функции наборы дескрипторов модифицируются, чтобы показать, какие из них изменили свой статус.

Для манипуляций наборами существуют четыре макроса: FD_ZERO очищает набор. FD_SET и FD_CLR добавляют или удаляют заданный дескриптор из набора. FD_ISSET проверяет, является ли дескриптор частью набора; этот макрос полезен после возврата из функции select.

n на единицу больше самого большого номера дескриптора из всех наборов.

timeout -- это верхняя граница времени, которое пройдет перед возвратом из select. Можно использовать ноль, при этом select завершится немедленно. (Это полезно для периодического опроса.) Если timeout равен NULL (нет тайм-аута), то select будет ожидать изменений неопределенное время.

sigmask -- это указатель на маску сигналов (см. sigprocmask(2)); если этот параметр не равен NULL, то pselect сначала замещает текущую маску сигналов на ту, на которую указывает sigmask, затем выполняет select, и восстанавливает исходную маску сигналов.

Идея pselect в том, что если нужно подождать события: сигнала или активности на файловом дескрипторе, то требуется атомарная проверка, чтобы предотвратить race condition. (Предположим, обработчик сигнала устанавливает глобальный флаг и возвращает управление. Тогда проверка этого глобального флага, за которой следует select(), может привести к подвисанию, если сигнал появляется сразу после проверки, но прямо перед вызовом select. С другой стороны, pselect позволяет сначала заблокировать сигналы, обработать пришедшие сигналы, а затем вызвать pselect() с желаемой sigmask, тем самым избегая race condition.) Так как Linux в настоящее время не содержит системного вызова pselect(), текущая реализация этой процедуры в glibc все еще содержит race condition.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном завершении select и pselect возвращают количество дескрипторов, находящихся в наборах дескрипторов, причем это количество может быть равным нулю, если тайм-аут истекает, а интересующие нас события так и не произошли. При ошибке возвращается −1, а errno устанавливается должным образом; наборы дескрипторов и значение timeout становятся неопределены, поэтому при ошибке нельзя полагаться на их значение.

ОШИБКИ

EBADF

В одном из наборов находится неверный файловый дескриптор.

EINTR

Был пойман незаблокированный сигнал.

EINVAL

n отрицательно.

ENOMEM

Функция select не смогла выделить участок памяти для внутренних таблиц.

ЗАМЕЧАНИЕ

В некоторых программах select вызывается с тремя пустыми наборами файлов, n равным нулю, и ненулевым значением timeout, что является довольно переносимым способом сделать задержку с миллисекундной точностью.

Под Linux timeout изменяется, чтобы сообщить количество времени, которое не было использовано; большинство других реализаций не делают этого. Это приводит к проблемам как в коде под Linux, который читает значение timeout и переносится в другие операционные системы, так и когда код переносится под Linux и использует при этом struct timeval для нескольких функций select в цикле без повторной инициализации. Считайте, что параметр timeout неопределен после возврата из функции select.

ПРИМЕР

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;

/* Ждем, пока на стандартном вводе (fd 0) что-нибудь
появится. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Ждем не больше пяти секунд. */
tv.tv_sec = 5;
tv.tv_usec = 0;

retval = select(1, &rfds, NULL, NULL, &tv);
/* Не полагаемся на значение tv! */

if (retval)
printf("Данные доступны.\n");
/* Теперь FD_ISSET(0, &rfds) вернет истинное значение. */
else
printf("Данные не появились в течение пяти секунд.\n");

exit(0);
}

СООТВЕТСТВИЕ СТАНДАРТАМ

4.4BSD (функция select впервые появилась в 4.2BSD). Обычно переносится с/на не-BSD системы, поддерживающие уровень BSD-сокетов (включая варианты System V). Однако заметьте, что варианты System V обычно устанавливают значение переменной timeout перед выходом, а вариант BSD -- нет.

Функция pselect определена в IEEE Std 1003.1g-2000 (POSIX.1g). Ее можно найти в glibc2.1 и позднее. Glibc2.0 содержит функцию с таким именем, но без параметра sigmask.

СМОТРИ ТАКЖЕ

accept(2), connect(2), poll(2), read(2), recv(2), send(2), sigprocmask(2), write(2)

ПЕРЕВОД

Copyright (C) Alexey Mahotkin <alexm [AT] hsys.ru> 2000-2001