Когда проверить EINTR и повторить вызов функции?

Я программирую пользовательское приложение для встроенной системы Linux и использую для устройств общие функции, такие как открытие, закрытие, чтение, ioctl и т. Д. Теперь, я прочитал о EINTR, указывает, что функция была прервана сигналом, но я не уверен в последствиях. Во всех примерах программ, которые у меня есть, иногда это делается, например, ioctl(), иногда это не делается, например, read(). Итак, я немного запутался.

Когда мне предпочтительно проверять EINTR и повторять вызов функции?

4 ответа

Решение

См. Sigaction: http://pubs.opengroup.org/onlinepubs/009695399/functions/sigaction.html

SA_RESTART
  This flag affects the behavior of interruptible functions; that is, those 
  specified to fail with errno set to EINTR. If set, and a function specified 
  as interruptible is interrupted by this signal, the function shall restart 
  and shall not fail with EINTR unless otherwise specified. If the flag is not 
  set, interruptible functions interrupted by this signal shall fail with errno 
  set to EINTR.

По умолчанию у вас есть поведение SA_RESTART, поэтому вам не нужно беспокоиться об EINTR, если вы не играете с сигналами.

Я знаю, что это старый вопрос, но я думаю, что еще нужно сказать. Чтобы ответить на конкретный вопрос в названии: в принципе, никогда.

Помимо select а также poll, EINTR может произойти, только если вы установили (либо по ошибке / не понимаете, как использовать sigaction, или потому что вы хотите иметь возможность прерывать блокирующие операции) прерывание обработчиков сигналов. Цикл для повторной попытки при сбое функцииEINTRпросто отменяет это. Это старый антипаттерн из 80-х и с начала до середины 90-х, когда многие операционные системы имели ошибки и, как сообщалось, генерировались.EINTR при несоответствующих обстоятельствах, но эти ошибки давно исчезли.

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

Управляется ли событие вашего приложения? (Имеется ввиду его основной цикл select()/epoll_wait() вызов).

В приложении, управляемом событиями, вы можете заблокировать все сигналы и разблокировать их только на время pselect()/epoll_pwait() вызов. Таким образом, остальная часть вашего кода никогда не будет иметь дело с EINTR.

Эта ссылка имеет довольно хорошее объяснение.

http://www.ibm.com/developerworks/linux/library/l-reent.html

Ура!

У меня была похожая проблема при ожидании ввода из именованного канала с помощью read().

Я нашел объяснение и полезный макрос для примитивов в документации GNU libc: TEMP_FAILURE_RETRY

Пример:

TEMP_FAILURE_RETRY (read_return = read((int)example_fifo, buffer, (size_t)n));
if (read_return==-1){
    fprintf(stderr, "reader.c: read_fifo: read(): %s \n", strerror(errno));
    fflush(stderr);
}
Другие вопросы по тегам