Почему select() продолжает работать с ошибкой EINTR errno?

У меня есть приложение C++, которое включает эту функцию:

int
mySelect(const int fdMaxPlus1,
         fd_set *readFDset,
         fd_set *writeFDset,
         struct timeval *timeout)
{
 retry:
  const int selectReturn
    = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, timeout);

  if (selectReturn < 0 && EINTR == errno) {
    // Interrupted system call, such as for profiling signal, try again.
    goto retry;
  }

  return selectReturn;
}

Обычно этот код работает просто отлично, однако, в одном случае, я видел, как он попал в бесконечный цикл, где select() продолжает терпеть неудачу с EINTRerrno код. В этом случае вызывающая сторона установила тайм-аут на ноль секунд и ноль микросекунд, то есть не ждать и вернуть select() результат сразу. я думал так EINTR происходит только тогда, когда произошел обработчик сигнала, почему я продолжал получать обработчик сигнала снова и снова (более 12 часов)? Это Centos 5. Как только я поместил это в отладчик, чтобы увидеть, что происходит, код вернулся без EINTR после нескольких итераций. Обратите внимание, что проверяемый fd является сокетом.

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

1 ответ

В Linux select(2) может изменить аргумент времени ожидания (передаваемый по адресу). Поэтому вы должны скопировать его после звонка.

retry:
struct timeout timeoutcopy = timeout;
const int selectReturn
  = ::select(fdMaxPlus1, readFDset, writeFDset, NULL, &timeoutcopy);

(в вашем коде ваш timeout вероятно, ноль или очень мало после нескольких или даже первых итераций)

Кстати, я предлагаю скорее использовать poll(2) вместо select (поскольку poll С10К более дружественный к проблеме)

КСТАТИ, EINTR происходит с любым сигналом (см. signal (7)), даже без зарегистрированного обработчика сигнала.

Вы могли бы использовать strace чтобы понять общее поведение вашей программы.

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