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

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

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

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

Ответ 1

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

SA_RESTART

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

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

Ответ 2

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

Как и в опубликованном POSIX 2008, это поведение разрешено:

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

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

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