errExit("write %d", pfds[randPipe][1]);
}
/* Формируем список файловых дескрипторов, которые передаются в poll().
Он должен содержать дескрипторы считывающих концов каждого из каналов. */
for (j = 0; j < numPipes; j++) {
pollFd[j].fd = pfds[j][0];
pollFd[j].events = POLLIN;
}
ready = poll(pollFd, numPipes, 0); /* Неблокирующий */
if (ready == -1)
errExit("poll");
printf("poll() returned: %d\n", ready);
/* Проверяем, в каких каналах есть данные, доступные для чтения */
for (j = 0; j < numPipes; j++)
if (pollFd[j].revents & POLLIN)
printf("Readable: %3d\n", pollFd[j].fd);
exit(EXIT_SUCCESS);
}
altio/poll_pipes.c
59.2.3. Условия готовности файлового дескриптора
Для правильного использования вызовов select() и poll() необходимо понимать условия, при которых файловый дескриптор считается готовым. Согласно стандарту SUSv3 это происходит, когда вызов функции ввода/вывода не блокируется
• столбец select() сигнализирует о том, помечен ли файловый дескриптор как доступный для чтения (r), записи (w) или имеющий исключительное условие (x);
• столбец poll() содержит бит(-ы), возвращаемые в поле revents. В этих таблицах не упоминаются флаги POLLRDNORM, POLLWRNORM, POLLRDBAND и POLLWRBAND. И хотя часть из них в определенных условиях может вернуться вместе с revents (если их указать в events), они не несут в себе никакой полезной информации, которую нельзя было бы получить с помощью флагов POLLIN, POLLOUT, POLLHUP и POLLERR.
Обычные файлы
Когда речь идет о дескрипторах, ссылающихся на обычные файлы, вызов select() помечает их доступными для чтения и записи, а вызов poll() устанавливает флаги POLLIN и POLLOUT в поле revents. Это объясняется следующими причинами:
• вызов read() в любой ситуации немедленно возвращает данные, конец файла или ошибку (например, если файл не был открыт для чтения);
• вызов write() всегда делает одно из двух: немедленно передает данные или сразу же завершается ошибкой.
Стандарт SUSv3 гласит, что, помимо прочего, вызов select() должен помечать дескриптор обычного файла как имеющий исключительное условие (хотя для обычных файлов значение этого факта совсем не очевидно). Так поступают не все системы; Linux в их число не входит.
Терминалы и псевдотерминалы
В табл. 59.3 описывается поведение вызовов select() и poll() для терминалов и псевдотерминалов (см. главу 60).
При закрытии одного из двух соединенных псевдотерминалов параметры revents, возвращаемые вызовом poll() для оставшегося конца соединения, зависят от реализации. В Linux как минимум устанавливается флаг POLLHUP. Хотя другие системы для оповещения об этом событии могут возвращать другие параметры, например POLLERR или POLLIN. Кроме того, в некоторых реализациях устанавливаемые флаги зависят от того, какое устройство отслеживалось — первичное или вторичное.
Таблица 59.3. Возвращаемые параметры вызовов select() и poll() для терминалов и псевдотерминалов
Условие или событие — select() — poll()
Доступен ввод — r — POLLIN
Возможен вывод — w — POLLOUT
После закрытия удаленного псевдотерминала — rw — См. текст
Первичный псевдотерминал в пакетном режиме обнаруживает изменение состояния вторичного конца соединения — x — POLLPRI
Именованные каналы и очереди FIFO
В табл. 59.4 собраны подробности о считывающем конце именованного канала и очереди FIFO. Столбец «Данные в канале?» указывает на то, можно ли прочитать из канала хотя бы один байт данных. Мы исходим из того, что поле events вызова poll() содержит флаг POLLIN.
Таблица 59.4. Параметры, возвращаемые вызовами select() и poll() для считывающего конца именованного канала и очереди FIFO
Условие или событие
select()
poll()
Данные в канале?
Записывающий конец открыт?
Нет
Нет
r
POLLHUP
Да
Да
r
POLLIN
Да
Нет
r
POLLIN | POLLHUP
В некоторых других реализациях UNIX, если записывающий конец канала закрыт, то вызов poll() возвращается с установленным флагом POLLIN (так как вызов read() сразу же возвращает конец файла), а не с POLLHUP. Проверяя возможность блокировки операции чтения, портируемые приложения должны учитывать оба эти бита.