poll()

Направлять ввод/вывод на различные файловые дескрипторы

Прототип:

#include <sys/poll.h>
int poll( struct pollfd *fds,
nfds_t nfds,
int timeout );

Аргументы:

fds
Массив элементов struct pollfd, который определяет интересующие файловые дескрипторы.
nfds
Количество элементов в массиве fds.
timeout
Предельное время ожидания в миллисекундах.

Библиотека:

libc

Описание:

Функция poll() предоставляет приложениям механизм мультиплексирования операций ввода/вывода над набором файловых дескрипторов.

Аргумент fds - это массив из структур struct pollfd.

Функция poll() проверяет каждый член массива файловых дескрипторов fds на предмет наличия событий, указанных в events. Количество структур struct pollfd в массиве fds определяется аргументом nfds. Членами массива являются структуры struct pollfd, внутри которых fd указывает на дескриптор открытого файла, а аргументы events и revents представляют собой битовые маски, построенные с помощью комбинации (операция ИЛИ) следующих флагов событий:

POLLERR
Произошла ошибка на устройстве. Этот флаг действителен только в битовой маске revents и игнорируется в events.
POLLHUP
Устройство было отключено. Это событие и POLLOUT являются взаимоисключающими; устройство не является доступным для записи, если до этого произошло его отключение. Однако это событие совместимо с POLLIN, POLLRDNORM, POLLRDBAND или POLLPRI. Если удаленный сокет закрыт, poll() возвращает событие POLLIN, а не POLLHUP. Этот флаг действителен только в битовой маске revents и игнорируется в events.
POLLIN
Данные могут быть прочитаны без блокировки, кроме данных с высоким приоритетом. Это эквивалент POLLRDNORM | POLLRDBAND.
POLLNVAL
Указано недопустимое значение файлового дескриптора. Этот флаг действителен только для члена revents и игнорируется в events.
POLLOUT
Обычные данные можно записывать без блокировки.
POLLPRI
Данные с высоким приоритетом можно читать без блокировки.
POLLRDBAND
Приоритетные данные можно читать без блокировки.
POLLRDNORM
Обычные данные можно читать без блокировки.
POLLWRBAND
Приоритетные данные могут быть записаны.
POLLWRNORM
Эквивалент POLLOUT.

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

Если значение fd меньше, чем 0, события events игнорируются, а для revents устанавливается значение 0 в этой записи при возврате из poll().

В каждой структуре struct pollfd poll() очищает элемент revents, за исключением тех случаев, когда приложение запрашивало отчет об условии, задав один из битов events, перечисленных выше, функция poll() устанавливает соответствующий бит в revents, если запрошенное условие истинно. Кроме того, функция poll() устанавливает флаг POLLHUP, POLLERR и POLLNVAL в revents, если условие истинно, даже если приложение не установило соответствующий бит в events.

Если ни одно из определенных событий не происходит ни в одном из выбранных файловых дескрипторов, функция poll() выдерживает timeout миллисекунд, чтобы событие произошло в любом из них. Если значение timeout равно 0, poll() возвращается немедленно. Если значение timeout равно -1, poll() блокируется до тех пор, пока не произойдет запрошенное событие или пока вызов не будет прерван.

Флаг O_NONBLOCK не влияет на функцию poll().

Функция poll() позволяет опрашивать обычные файлы, терминальные и псевдотерминальные устройства, FIFO и каналы.

Обычные файлы обычно имеют статус TRUE на чтение и запись.

Дескриптор файла для сокета, который прослушивает соединения, указывает, что он готов к чтению, как только соединения станут доступны. Дескриптор файла для сокета, который подключается асинхронно, указывает, что он готов к записи после того, как соединение было установлено.

Возвращаемое значение:

>0
Общее количество выбранных файловых дескрипторов.
0
Истекло время ожидания вызова, но не один дескриптор файлов не выбран.
-1
Возникла ошибка. Код ошибки записан в errno.

Коды ошибок:

EAGAIN
Не удалось выделить внутренние структуры данных, но последующий запрос может быть успешным.
EINTR
Получен сигнал во время выполнения poll().
EFAULT
Аргумент fds указывает на несуществующую часть адресного пространства вызывающего процесса.

Примеры:

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
struct sockaddr_in sad;
void * client( void *arg )
{
int s;
const char *p = "Some data\n";
if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
{
perror( "socket" );
return (NULL);
}
if ( connect( s, (struct sockaddr *)&sad, sizeof( sad ) ) == -1 )
{
perror("connect");
return (NULL);
}
write( s, p, strlen( p ) );
close( s );
return (NULL);
}
int main( void )
{
struct pollfd fds;
int s = -1, s2 = -1, done_accept = 0, oflags, ret;
char buf[100];
if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 )
{
perror( "socket" );
return (1);
}
sad.sin_family = AF_INET;
sad.sin_len = sizeof( sad );
sad.sin_addr.s_addr = inet_addr( "127.0.0.1" );
sad.sin_port = htons( 1234 );
fds.fd = s;
fds.events = POLLRDNORM;
oflags = fcntl( s, F_GETFL );
oflags |= O_NONBLOCK;
fcntl( s, F_SETFL, oflags );
if ( bind( s, (struct sockaddr *)&sad, sizeof( sad ) ) == -1 )
{
perror( "bind" );
return (1);
}
listen( s, 5 );
if ( (ret = pthread_create( NULL, NULL, client, NULL )) != EOK )
{
fprintf( stderr, "pthread_create: %s\n", strerror( ret ) );
return (1);
}
for ( ; ; )
{
if ( (ret = poll( &fds, 1, -1 )) == -1 )
{
perror( "poll" );
break;
} else
if ( ret != 1 || (fds.revents & POLLRDNORM) == 0 )
{
break;
}
if ( done_accept )
{
if ( (ret = read( s2, buf, sizeof( buf ) )) <= 0 )
{
break;
}
printf( "%s", buf );
} else {
if ( (s2 = accept( s, NULL, 0 )) == -1 )
{
perror( "accept" );
break;
}
fds.fd = s2;
done_accept = 1;
}
}
close( s );
close( s2 );
return (0);
}

Классификация:

POSIX 1003.1 X/Open Systems Interfaces Extension

Безопасность использования
Точка остановки потока
Да
Обработчик прерываний
Нет
Обработчик сигналов
Нет
В потоке
Да

Предостережения:

Не все менеджеры поддерживают POLLPRI, POLLPRI, POLLERR и POLLHUP.

Тематические ссылки:

struct pollfd, read(), select(), write()




Предыдущий раздел: Описание API системной библиотеки