Из чтения страниц справочника по вызовам read()
и write()
вызовам выясняется, что эти вызовы прерываются сигналами независимо от того, должны они блокировать или нет.
В частности, предположим
- процесс устанавливает обработчик для некоторого сигнала.
- устройство открыто (скажем, терминал) с
O_NONBLOCK
не установленным (т.е. работает в режиме блокировки) - затем процесс выполняет
read()
системный вызов для чтения с устройства и в результате выполняет путь управления ядром в пространстве ядра. - в то время как прецесс выполняет его
read()
в пространстве ядра, сигнал, для которого был установлен ранее обработчик, доставляется этому процессу, и вызывается его обработчик сигнала.
Читая справочные страницы и соответствующие разделы SUSv3 «Объем системных интерфейсов (XSH)» , можно обнаружить, что:
я. Если a read()
прервано сигналом до того, как он прочитает какие-либо данные (т. errno
Е. Ему пришлось заблокировать, потому что данные не были доступны), он возвращает -1 с установленным на [EINTR].
II. Если a read()
прервано сигналом после того, как он успешно прочитал некоторые данные (т. Е. Было возможно немедленно начать обслуживание запроса), он возвращает количество прочитанных байтов.
Вопрос A):
Правильно ли предположить, что в любом случае (блок / нет блока) доставка и обработка сигнала не полностью прозрачны для read()
?
Случай I. кажется понятным, поскольку блокировка read()
обычно переводит процесс в TASK_INTERRUPTIBLE
состояние, так что при доставке сигнала ядро переводит процесс в TASK_RUNNING
состояние.
Однако, когда read()
блок не нужно блокировать (случай ii.) И обрабатывает запрос в пространстве ядра, я бы подумал, что поступление сигнала и его обработка будут прозрачными во многом как поступление и правильная обработка HW Прерывание будет. В частности, я бы предположил, что после доставки сигнала процесс будет временно переведен в пользовательский режим для выполнения его обработчика сигнала, из которого он в конечном итоге вернется, чтобы завершить обработку прерванного read()
(в пространстве ядра), чтобы read()
запустить его переход к завершению, после которого процесс возвращается к точке сразу после вызова read()
(в пользовательском пространстве) со всеми доступными байтами, считанными в результате.
Но ii. кажется, подразумевает, что read()
прервано, поскольку данные доступны сразу, но он возвращает возвращает только некоторые данные (вместо всех).
Это подводит меня ко второму (и последнему) вопросу:
Вопрос B):
Если мое предположение в соответствии с пунктом А) является верным, почему read()
прерывание происходит, даже если ему не нужно блокировать, потому что есть данные, доступные для немедленного удовлетворения запроса? Другими словами, почему read()
не возобновляется после выполнения обработчика сигнала, что в конечном итоге приводит к возвращению всех доступных данных (которые были доступны в конце концов)?
источник
Чтобы ответить на вопрос А :
Да, доставка и обработка сигнала не совсем прозрачны для
read()
.read()
Работает на полпути может занимать несколько ресурсов , в то время как она прерывается сигналом. И обработчик сигнала может также вызывать другиеread()
(или любые другие безопасные асинхронные сигналы ). Таким образом,read()
прерванный сигналом должен быть сначала остановлен, чтобы высвободить ресурсы, которые он использует, в противном случаеread()
вызываемый из обработчика сигнала получит доступ к тем же ресурсам и вызовет повторяющиеся проблемы.Потому что системные вызовы, отличные от тех, которые
read()
могут быть вызваны из обработчика сигнала, могут также занимать идентичный набор ресурсов, как иread()
раньше Чтобы избежать повторяющихся проблем, описанных выше, самый простой и безопасный способ - останавливать прерываниеread()
каждый раз, когда происходит сигнал во время его работы.источник