Как узнать, перезапускается ли системный вызов 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.