• Бит POLLWRBAND устанавливается в некоторых случаях, но не несет в себе никакой полезной информации (кроме того, его нельзя установить без использования битов POLLOUT и POLLWRNORM).
• Для получения определений констант POLLRDNORM, POLLRDBAND, POLLWRNORM и POLLWRBAND из заголовочного файла
• Флаг POLLRDHUP применяется только в Linux и только с версией ядра 2.6.17. Чтобы получить его определение из файла
• Бит POLLNVAL возвращается, если на момент вызова poll() заданный файловый дескриптор был закрыт.
Подводя итог всему вышесказанному, наиболее важными флагами вызова poll() являются POLLIN, POLLOUT, POLLPRI, POLLRDHUP, POLLHUP и POLLERR. Их назначение будет подробно описано в подразделе 59.2.3.
Аргумент timeout
Аргумент timeout влияет на блокировку вызова poll():
• если он равен –1, то блокировка происходит до тех пор, пока не станет готовым хотя бы один файловый дескриптор из массива fds (в соответствии с полем events) или не будет перехвачен сигнал;
• если он равен 0, то вызов проверяет готовность дескрипторов, не блокируясь;
• если он больше нуля, то блокировка происходит на протяжении timeout миллисекунд, пока не станет готовым один из файловых дескрипторов в массиве fds или не будет перехвачен сигнал.
Как и в случае с вызовом select(), точность аргумента timeout ограничена системными часами (см. раздел 10.6). А в стандарте SUSv3 сказано, что время ожидания округляется в большую сторону, если оно не делится без остатка.
Значение, возвращаемое вызовом poll()
В качестве результата вызов poll() возвращает одно из следующих значений:
• –1 в случае ошибки. Одной из возможных ошибок является EINTR, которая говорит о том, что вызов был прерван обработчиком сигнала (как отмечалось в разделе 21.5, в этой ситуации вызов poll() никогда не перезапускается автоматически);
• 0, если время ожидания истекло до того, как любой из файловых дескрипторов стал готовым;
• положительное значение, если один или несколько дескрипторов оказались готовыми. Это значение соответствует количеству структур pollfd в массиве fds, которые имеют ненулевое поле revents.
Стоит отметить, что положительные значения, возвращаемые вызовами select() и poll(), имеют немного разный смысл. Системный вызов select() может учесть один и тот же файловый дескриптор несколько раз, если он входит сразу в несколько итоговых наборов. Системный вызов poll() возвращает количество готовых файловых дескрипторов, любой из которых может быть учтен лишь один раз, даже если в соответствующем поле revents установлено несколько битов.
Пример программы
Простой пример использования вызова poll() демонстрируется в листинге 59.2. Программа создает несколько именованных каналов (каждый из которых задействует по два файловых дескриптора с соседними номерами), записывает байты во входящий конец одного из них, выбранного случайным образом, и затем выполняет вызов poll(), чтобы узнать, в каком канале можно прочитать данные.
Пример выполнения показан в следующей сессии командной строки. Согласно предоставленным аргументам программа должна создать десять именованных каналов и выполнить запись в три из них (выбранных произвольно).
$ ./poll_pipes 10 3
Writing to fd: 4 (read fd: 3)
Writing to fd: 14 (read fd: 13)
Writing to fd: 14 (read fd: 13)
poll() returned: 2
Readable: 3
Readable: 13
Как видите, вызов poll() нашел два канала с данными, доступными для чтения.
Листинг 59.2. Использование вызова poll() для мониторинга нескольких файловых дескрипторов
altio/poll_pipes.c
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int numPipes, j, ready, randPipe, numWrites;
int (*pfds)[2]; /* Файловые дескрипторы для всех каналов */
struct pollfd *pollFd;
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s num-pipes [num-writes]\n", argv[0]);
/* Выделяем место для наших массивов. Их размеры соответствуют
количеству каналов, заданному в командной строке */
numPipes = getInt(argv[1], GN_GT_0, "num-pipes");
pfds = calloc(numPipes, sizeof(int [2]));
if (pfds == NULL)
errExit("calloc");
pollFd = calloc(numPipes, sizeof(struct pollfd));
if (pollFd == NULL)
errExit("calloc");
/* Создаем столько каналов, сколько указано в командной строке */
for (j = 0; j < numPipes; j++)
if (pipe(pfds[j]) == -1)
errExit("pipe %d", j);
/* Выполняем заданное число операций записи в произвольные каналы */
numWrites = (argc > 2)? getInt(argv[2], GN_GT_0, "num-writes"): 1;
srandom((int) time(NULL));
for (j = 0; j < numWrites; j++) {
randPipe = random() % numPipes;
printf("Writing to fd: %3d (read fd: %3d)\n",
pfds[randPipe][1], pfds[randPipe][0]);
if (write(pfds[randPipe][1], "a", 1) == -1)