POLLHUP против POLLNVAL, или что такое POLLHUP?

Руководства говорят для опроса (2):

POLLHUP - повесить трубку (только вывод)

POLLNVAL - Неверный запрос: fd не открыт (только вывод)

В чем именно разница? Написание простой программы показывает, что POLLNVAL сработает, если я закрою дескриптор файла, затем попробую прочитать с закрытого fd. Тем не менее, я не могу найти способ вернуть POLLHUP,

3 ответа

Решение

POLLNVAL эквивалентно EBADF: это означает, что дескриптор файла на самом деле не ссылается ни на один открытый файл, т.е. closeг или никогда не открывать для начала. Это никогда не может произойти, кроме как в результате ошибки программирования или преднамеренной попытки запросить, является ли дескриптор файла недействительным. Внешние условия, такие как одноранговый узел, закрывающий свой конец сетевого сокета или канала, никогда не могут закрыть ваш файловый дескриптор до вашего конца сокета или канала. Если бы это было возможно, это привело бы к огромным уязвимостям практически любой программы, использующей сокеты / каналы / и т.д.

POLLHUPс другой стороны, указывает, что ваш дескриптор файла действителен, но находится в состоянии, где:

Устройство было отключено или канал или FIFO были закрыты последним процессом, открывшим его для записи. После установки состояние зависания FIFO должно сохраняться до тех пор, пока какой-либо процесс не откроет FIFO для записи или пока не будут закрыты все файловые дескрипторы только для чтения для FIFO. Это событие и ПРОДАЖА являются взаимоисключающими; поток никогда не может быть доступен для записи, если произошло зависание. Однако это событие и POLLIN, POLLRDNORM, POLLRDBAND или POLLPRI не являются взаимоисключающими. Этот флаг действителен только в битовой маске это должно быть проигнорировано в участнике событий.

Источник: http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html

Если вы хотите увидеть POLLHUPПросто откройте pipeзакройте конец чтения и запросите конец записи с помощью poll,

Если ваша цель - написать программу, которая запускает POLLHUPпопробуйте что-то вроде открытия канала, закрытия конца записи и затем poll()конец чтения (код изменен с http://www.greenend.org.uk/rjk/tech/poll.html):

#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(void)
{
    int p[2];
    struct pollfd ufd;

    if (pipe(p) < 0) {
        perror("pipe");
        return EXIT_FAILURE;
    }
    if (close(p[1]) < 0) { /* close the write fd */
        perror("close");
        return EXIT_FAILURE;
    }

    memset(&ufd, 0, sizeof ufd);
    ufd.fd = p[0]; /* poll the read fd after the write fd is closed */
    ufd.events = POLLIN;
    if (poll(&ufd, 1, 1000) < 0) {
        perror("poll");
        return EXIT_FAILURE;
    }

    switch(ufd.revents & (POLLIN|POLLHUP)) {
        case POLLIN: printf("POLLIN\n"); break;
        case POLLHUP: printf("POLLHUP\n"); break;
        case POLLIN|POLLHUP: printf("POLLIN|POLLHUP\n"); break;
        case POLLERR: printf("POLLERR\n"); break;
        default: printf("%#x\n", (unsigned)ufd.revents); break;
    }

    return EXIT_SUCCESS;
}

Вышеуказанные принты POLLHUP для меня.

POLLNVAL означает, что значение дескриптора файла недопустимо. Обычно это указывает на ошибку в вашей программе, но вы можете положиться на poll возврате POLLNVAL если вы закрыли файловый дескриптор и с тех пор не открыли ни одного файла, возможно, этот дескриптор использовался повторно.

POLLHUP в основном означает, что то, что находится на другом конце соединения, закрыло свой конец соединения. POSIX описывает это как

Устройство было отключено. Это событие и ПРОДАЖА являются взаимоисключающими; поток никогда не может быть доступен для записи, если произошло зависание.

Это достаточно ясно для терминала: терминал ушел (то же самое событие, которое генерирует SIGHUP: сеанс модема был завершен, окно эмулятора терминала было закрыто и т. Д.). POLLHUP никогда не отправляется для обычного файла. Для труб и розеток это зависит. Наборы Linux POLLHUP когда программа на конце записи канала закрывает канал и устанавливает POLLIN|POLLHUP когда другой конец сокета закрыл сокет, но POLLIN только для отключения розетки. Недавний *BSD набор POLLIN|POLLUP когда записывающий конец канала закрывает канал, и поведение для сокетов более изменчиво.

Наблюдать POLLHUP, прочитайте вашу программу из терминала и закройте терминал. Или, в Linux, ваша программа читает из канала и закрывает конец записи (например, sleep 1 | yourprogram).

Другие вопросы по тегам