Мы поговорим о функции
pselect
более подробно и приведем ее пример в разделе 20.5. Функцию
pselect
мы используем в листинге 20.3, а в листинге 20.4 показываем простую, хотя и не вполне корректную реализацию этой функции.
ПРИМЕЧАНИЕ
Есть одно незначительное различие между функциями select и pselect. Первый элемент структуры timeval является целым числом типа long со знаком, в то время как первый элемент структуры timspec имеет тип time_t. Число типа long со знаком в первой функции также должно было относиться к типу time_t, но мы не меняли его тип, чтобы не разрушать существующего кода. Однако в новой функции это можно было бы сделать.
6.10. Функция poll
Функция
poll
появилась впервые в SVR3, и изначально ее применение ограничивалось потоковыми устройствами (STREAMS devices) (см. главу 31). В SVR4 это ограничение было снято, что позволило функции
poll
работать с любыми дескрипторами. Функция
poll
предоставляет функциональность, аналогичную функции
select
, но позволяет получать дополнительную информацию при работе с потоковыми устройствами.
#include <poll.h>
int poll(struct pollfd *<i>fdarray</i>, unsigned long <i>nfds</i>, int <i>timeout</i>);
<i>Возвращает: количество готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки</i>
Первый аргумент — это указатель на первый элемент массива структур. Каждый элемент массива — это структура
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
.