2015-11-24 3 views
3

я в настоящее время добавления sockfds, созданный из accept к Epoll например со следующими событиями:Epoll с запуском по фронту и OneShot сообщает только один раз

const int EVENTS = (
    EPOLLET | 
    EPOLLIN | 
    EPOLLRDHUP | 
    EPOLLONESHOT | 
    EPOLLERR | 
    EPOLLHUP); 

Когда событие срабатывает, я передаю его в обработчик поток, прочитайте, а затем снова включите sockfd через epoll_ctl с теми же флагами. Тем не менее, я получаю только событие EPOLLIN один раз. Кроме того, если я убью клиента в любое время после получения первого события, я тоже не получаю события отвлечения. Из чтения man-страниц, я думал, что понял правильный подход с EdgeTriggered и OneShot.

Ниже приведены некоторые псевдо-код для процесса я использую:

const int EVENTS = (
    EPOLLET | 
    EPOLLIN | 
    EPOLLRDHUP | 
    EPOLLONESHOT | 
    EPOLLERR | 
    EPOLLHUP); 

void event_loop() 
{ 
    struct epoll_event event; 
    struct epoll_event *events; 
    events = calloc(100, sizeof event); 
    while (1) 
    { 
     int x; 
     int num_events = epoll_wait(epfd, events, 100, -1); 
     for (x = 0; x < num_events; x++) 
     { 
      another_thread(fd); 
     } 
    } 
} 

void another_thread(int fd) 
{ 
    // Read stuff until EAGAIN 

    struct epoll_event event; 
    event.data.fd = fd; 
    event.events = EVENTS; 
    epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event); 
} 

Когда я делаю EPOLL_CTL_MOD операцию, я не получаю никаких ошибок, но никогда не получал уведомления о других событиях. Если я оставлю цикл чтения после повторения после первого события, он будет читать все последующие данные, отправленные клиентом, поэтому я знаю, что данные поступают, а fd все еще открыт и работает.

От проверки strace, потоки создаются с clone и имеют флаг CLONE_FILES, поэтому все потоки разделяют одну и ту же таблицу fd.

Каков правильный способ повторного включения fd для чтения событий из отдельного потока?

+0

MCVE поможет много. Например, псевдокод не объясняет взаимосвязи между циклом события и потоками обработчика.Здесь есть три «движущиеся части»: EPOLLET (вы пробовали свой код без этого флага?), EPOLLONESHOT и многопоточность. Таким образом, диагностика проблемы _real_ соответственно затруднена. – arayq2

ответ

0

Однако, я получаю только событие EPOLLIN один раз. Кроме того, если я убью клиента в любое время после получения первого события, я тоже не получаю события отвлечения.

человек страница epoll_ctl (2) говорит, что:

EPOLLONESHOT (с Linux 2.6.2) Задает поведение однократный для соответствующего дескриптора файла. Это означает, что после того, как событие вытащено с epoll_wait (2) связанный файловый дескриптор внутренне отключен, и никакие другие события не будут сообщены интерфейсом epoll . Пользователь должен вызвать epoll_ctl() с помощью EPOLL_CTL_MOD , чтобы переделать файловый дескриптор с помощью новой маски события.

В вашем случае, когда вы получаете первое событие, Epoll отключает свой sockfd. При повторном включении вашего sockfd с помощью EPOLL_CTL_MOD он уведомит вас все события, которые получены ядром после перерегистрация. Поэтому любое событие между первым уведомлением и перерегистрацией будет потеряно. Это может быть причиной не получения каких-либо событий или данных зависания.

Удаление EPOLLONESHOT из событий будет исправлять ваш код, в конце концов вам не нужно снова включать sockfd.

И поскольку вы используете EPOLLET, также не будет проблем с производительностью.

+0

Это не тот случай, у меня есть серьезные 3-5-секундные задержки в клиентском коде, чтобы проверить этот случай, и я вижу сообщения журнала, которые fd был подготовлен, прежде чем клиент попытается отправить снова. Удаление флага одного выстрела не влияет :( – nathansizemore

+0

вы даете 3-5 секунд задержки клиенту, чтобы проверить, получаете ли вы событие «EPOLLRDHUP» или просто задержка между двумя отправками? – dktrivedi

+0

Задержка между двумя отправками. – nathansizemore