Как узнать, перезапускается ли системный вызов Linux или нет?

Некоторые системные вызовы могут быть прозрачно перезапущены ядром, если SA_RESTART Флаг используется при установке обработчика сигнала, в соответствии с сигналом человека (7):

Если заблокированный вызов одного из следующих интерфейсов прерывается обработчиком сигнала, то вызов будет автоматически перезапущен после того, как обработчик сигнала вернется, если был использован флаг SA_RESTART; в противном случае вызов не будет выполнен с ошибкой EINTR:

Затем упоминаются некоторые системные вызовы, которые могут (и не могут) быть перезапущены, но не упоминаются close() в любом месте, как бы я узнал, если close() или любая другая функция, перезапускается или нет? делает POSIX указать это или это специфичное для Linux поведение? где я могу найти больше информации?

2 ответа

Решение

Согласно POSIX.1-2008, SA_RESTART флаг применяется ко всем прерываемым функциям (все функции, которые задокументированы как сбойные с EINTR):

SA_RESTART

Этот флаг влияет на поведение прерываемых функций; то есть, те, которые указаны как сбойные с errno, установленным в [EINTR]. Если установлено, и функция, указанная как прерываемая, прерывается этим сигналом, функция должна перезапуститься и не должна выходить из строя с [EINTR], если не указано иное. Если прерываемая функция, использующая тайм-аут, перезапускается, продолжительность тайм-аута после перезапуска устанавливается равной неопределенному значению, которое не превышает первоначальное значение тайм-аута. Если флаг не установлен, прерываемые функции, прерываемые этим сигналом, должны потерпеть неудачу с ошибкой, установленной на [EINTR].

То есть список функций, которые не перезапускаются, зависит от Linux (и, вероятно, считается ошибкой).

close это довольно особый случай. Мало того, что это не перезапускается на Linux; когда close возвращается с EINTR в Linux это на самом деле уже удалось, и сделать еще один вызов close потерпит неудачу с EBADF в однопоточных процессах и вызывают чрезвычайно опасные гонки файловых дескрипторов в многопоточных процессах.

Начиная с опубликованного POSIX 2008, такое поведение разрешено:

Если close() прерывается сигналом, который должен быть перехвачен, он должен вернуть -1 с errno, установленным в [EINTR], и состояние файлов не определено.

Эта проблема была поднята с Austin Group (как проблема № 529), и было решено пересмотреть спецификацию, чтобы вернуться с EINTR означает, что дескриптор файла все еще открыт; это противоречит текущему поведению Linux. Если дескриптор файла уже был закрыт во время обработки сигнала, close функция теперь требуется для возврата с EINPROGRESS вместо EINTR, Это может быть исправлено в пользовательском пространстве в Linux, и есть открытый отчет об ошибке glibc, #14627 для него, но на момент написания статьи он не получил никакого ответа.

Эта проблема также имеет серьезные последствия для отмены потока POSIX, побочные эффекты которого указаны в терминах побочных эффектов при возврате с EINTR, Существует проблема, связанная с трекером Austin Group, выпуск № 614.

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