Неверное поведение EPOLLET? - PullRequest
0 голосов
/ 10 мая 2018

Пожалуйста, рассмотрите следующую программу:

#define _GNU_SOURCE
#include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

int verify(int result, const char *msg) {
    if( result>=0 )
        return result;

    perror(msg);
    abort();

    return -1;
}

void writepipe( int fd, int num_bytes, const char *msg ) {
    unsigned char buffer[num_bytes];
    ssize_t num_written = verify( write(fd, buffer, num_bytes), msg );
    assert( num_written==num_bytes );
}

void readpipe( int fd, int num_bytes, const char *msg ) {
    unsigned char buffer[num_bytes];
    ssize_t num_read = verify( read(fd, buffer, num_bytes), msg );
    assert( num_read==num_bytes );
}

int main() {
    int pipefds[2];
    verify( pipe2(pipefds, O_NONBLOCK), "pipe creation failed" );

    int epollfd = verify(epoll_create1(0), "epoll creation failed");

    struct epoll_event evt;
    evt.events = EPOLLIN|EPOLLET;
    evt.data.u64 = 17;
    verify( epoll_ctl( epollfd, EPOLL_CTL_ADD, pipefds[0], &evt ), "epoll_add failed" );

    int num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
    assert(num_events == 0);

    writepipe( pipefds[1], 12, "initial filling of pipe" );

    num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
    assert(num_events == 1);
    assert(evt.data.u64 == 17);

    num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
    assert(num_events == 0);

    readpipe( pipefds[0], 12, "clean the data" );

    num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait failed" );
    assert(num_events == 0);

    writepipe( pipefds[1], 3, "write no trigger" );

    num_events = verify( epoll_wait(epollfd, &evt, 1, 0), "epoll_wait on unarmed fd" );
    assert(num_events == 0);

    return 0;
}

Последнее утверждение не выполнено.

Поскольку нам никогда не удавалось прочитать EPOLLET из эполла, я ожидал, что последний epoll_wait вернет 0. Вместо этого я получу 1.

Почему это?

Ядро 4.13.0-39-generic из Ubuntu 16.10.

1 Ответ

0 голосов
/ 06 декабря 2018

Поздний ответ, но, возможно, все еще полезен для других.

В вашем последнем вызове epoll_wait вы предполагаете, что fd безоружен.Это не вариант.Если вы действительно хотите, чтобы он был безоружен, вы можете использовать EPOLLONESHOT.После того, как это сработает один раз, вы должны перевооружить его для эполла.Вы также можете предположить, что вторая запись не вызывает срабатывание epoll.Это предположение тоже неверно.EPOLLET только гарантирует, что EPOLLET не сработает снова, если на FD нет изменений.Запись в канал запускает изменение, поэтому запускается эполл (не обязательно то, что ожидают люди).

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

источник: http://man7.org/linux/man-pages/man7/epoll.7.html

Я действительно не знаю, что вы имеете в виду под "мы никогда не читали EPOLLET", вы имеете в виду EAGAIN, чтосигнализирует, что все данные были прочитаны?Это на самом деле не имеет отношения к вашей проблеме.Вы полностью опустошите трубу.Таким образом, следующее чтение вызовет EAGAIN, но это не изменит поведения, упомянутого выше.Даже если вы не читаете данные, вторая запись вызовет эполл.Проверка на EAGAIN состоит в том, чтобы убедиться, что мы полностью прочитали все данные, если в дескрипторе файла нет изменений.

...