6.10. Функция poll
6.10. Функция poll
Функция poll появилась впервые в SVR3, и изначально ее применение ограничивалось потоковыми устройствами (STREAMS devices) (см. главу 31). В SVR4 это ограничение было снято, что позволило функции poll работать с любыми дескрипторами. Функция poll предоставляет функциональность, аналогичную функции select, но позволяет получать дополнительную информацию при работе с потоковыми устройствами.
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
Возвращает: количество готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки
Первый аргумент — это указатель на первый элемент массива структур. Каждый элемент массива — это структура pollfd, задающая условия, проверяемые для данного дескриптора fd.
struct pollfd {
int fd; /* дескриптор, который нужно проверить */
short events; /* события на дескрипторе, которые нас интересуют */
short revents; /* события, произошедшие на дескрипторе fd */
};
Проверяемые условия задаются элементом events, и состояние этого дескриптора функция возвращает в соответствующем элементе revents. (Наличие двух переменных для каждого дескриптора, одна из которых — значение, а вторая — результат, дает возможность обойтись без аргументов типа «значение-результат». Вспомните, что три средних аргумента функции select имеют тип «значение-результат».) Каждый из двух элементов состоит из одного или более битов, задающих определенное условие. В табл. 6.2 перечислены константы, используемые для задания флага events и для проверки флага revents.
Таблица 6.2. Различные значения флагов events и revents для функции poll
Константа На входе (events) На выходе (revents) Описание POLLIN • • Можно считывать обычные или приоритетные данные POLLRDNORM • • Можно считывать обычные данные POLLRDBAND • • Можно считывать приоритетные данные POLLPRI • • Можно считывать данные с высоким приоритетом POLLOUT • • Можно записывать обычные данные POLLWRNORM • • Можно записывать обычные данные POLLWRBAND • • Можно записывать приоритетные данные POLLERR • Произошла ошибка POLLHUP • Произошел разрыв соединения POLLNVAL • Дескриптор не соответствует открытому файлуМы разделили эту таблицу на три части: первые четыре константы относятся ко вводу, следующие три — к выводу, а последние три — к ошибкам. Обратите внимание, что последние три константы не могут устанавливаться в элементе events, но всегда возвращаются в revents, когда выполняется соответствующее условие.
Существует три класса данных, различаемых функцией poll: обычные, приоритетные и данные с высоким приоритетом. Эти термины берут начало в реализациях, основанных на потоках (см. рис. 31.5).
ПРИМЕЧАНИЕ
Константа POLLIN может быть задана путем логического сложения констант POLLRDNORM и POLLRDBAND. Константа POLLIN существовала еще в реализациях SVR3, которые предшествовали полосам приоритета в SVR4, то есть эта константа существует в целях обратной совместимости. Аналогично, константа POLLOUT эквивалентна POLLWRNORM, и первая из них предшествовала второй.
Для сокетов TCP и UDP при описанных условиях функция poll возвращает указанный флаг revent. К сожалению, в определении функции poll стандарта POSIX имеется множество слабых мест (неоднозначностей):
? Все регулярные данные TCP и все данные UDP считаются обычными.
? Внеполосные данные TCP (см. главу 24) считаются приоритетными.
? Когда считывающая половина соединения TCP закрывается (например, если получен сегмент FIN), это также считается равнозначным обычным данным, и последующая операция чтения возвратит нуль.
? Наличие ошибки для соединения TCP может расцениваться либо как обычные данные, либо как ошибка (POLLERR). В любом случае последующая функция read возвращает -1, что сопровождается установкой переменной errno в соответствующее значение. Это происходит при получении RST или истечении таймера.
? Информация о доступности нового соединения на прослушиваемом сокете может считаться либо обычными, либо приоритетными данными. В большинстве реализаций эта информация рассматривается как обычные данные.
Число элементов в массиве структур задается аргументом nfds.
ПРИМЕЧАНИЕ
Исторически этот аргумент имел тип long без знака, что является некоторым излишеством. Достаточно будет типа int без знака. В Unix 98 для этого аргумента определяется новый тип — nfds_t.
Аргумент timeout определяет, как долго функция находится в ожидании перед завершением. Положительным значением задается количество миллисекунд — время ожидания. В табл. 6.3 показаны возможные значения аргумента timeout.
Таблица 6.3. Значения аргумента timeout для функции poll
Значение аргумента timeout Описание INFTIM Ждать вечно 0 Возвращать управление немедленно, без блокирования >0 Ждать в течение указанного числа миллисекундКонстанта INFTIM определена как отрицательное значение. Если таймер в данной системе не обеспечивает точность порядка миллисекунд, значение округляется в большую сторону до ближайшего поддерживаемого значения.
ПРИМЕЧАНИЕ
POSIX требует, чтобы константа INFTIM была определена в заголовочном файле <poll.h>, но многие системы все еще определяют ее в заголовочном файле <sys/stropts.h>.
Как и в случае функции select, любой тайм-аут, установленный для функции poll, ограничивается снизу разрешающей способностью часов в конкретной реализации (обычно 10 мс).
Функция poll возвращает -1, если произошла ошибка, 0 — если нет готовых дескрипторов до истечения времени таймера, иначе возвращается число дескрипторов с ненулевым элементом revents.
Если нас больше не интересует конкретный дескриптор, достаточно установить элемент fd структуры pollfd равным отрицательному значению. В этом случае элемент events будет проигнорирован, а элемент revents при возвращении функции будет сброшен в нуль.
Вспомните наши рассуждения в конце раздела 6.3 относительно константы FD_SETSIZE и максимального числа дескрипторов в наборе в сравнении с максимальным числом дескрипторов для процесса. У нас не возникает подобных проблем с функцией poll, поскольку вызывающий процесс отвечает за размещение массива структур pollfd в памяти и за последующее сообщение ядру числа элементов в массиве. Не существует типа данных фиксированного размера, аналогичного fd_set, о котором знает ядро.
ПРИМЕЧАНИЕ
POSIX требует наличия и функции select, и функции poll. Но если сравнивать их с точки зрения переносимости, то функцию select в настоящее время поддерживает больше систем, чем функцию poll. POSIX определяет также функцию pselect — усовершенствованную версию функции select, которая обеспечивает возможность блокирования сигналов и предоставляет лучшую разрешающую способность по времени, а для функции poll ничего подобного в POSIX нет.
Данный текст является ознакомительным фрагментом.