Прерывание системных вызовов при перехвате сигнала - PullRequest
0 голосов
/ 11 июля 2011

Из чтения страниц справочника по вызовам read () и write () выясняется, что эти вызовы прерываются сигналами независимо от того, должны они блокировать или нет.

В частности,предположим, что

  • процесс устанавливает обработчик для некоторого сигнала.
  • устройство открыто (скажем, терминал ....) с НЕ установленным значением O_NONBLOCK (т.е. работает в режиме блокировки)mode)
  • затем процесс выполняет системный вызов read () для чтения с устройства и в результате выполняет путь управления ядром в пространстве ядра.
  • во время выполнения прецессииего read () в пространстве ядра, сигнал, для которого был установлен ранее обработчик, доставляется этому процессу, и вызывается его обработчик сигнала.

Чтение страниц руководства и соответствующих разделов вSUSv3 «Том системных интерфейсов (XSH)», который можно найти:

i.Если read () прерывается сигналом до того, как он прочитает какие-либо данные (т. Е. Ему пришлось заблокировать, потому что данные не были доступны), он возвращает -1 с 'errno', установленным в [EINTR].

ii.Если read () прерывается сигналом после того, как он успешно прочитал некоторые данные (т. Е. Можно было немедленно начать обслуживание запроса), он возвращает число прочитанных байтов

Вопрос A):

Правильно ли предположить, что в любом случае (блок / без блока) доставка и обработка сигнала не полностью прозрачны для read ()?

Случай i.кажется понятным, поскольку блокировка read () обычно переводит процесс в состояние «TASK_INTERRUPTIBLE», так что когда сигнал доставляется, ядро ​​переводит процесс в состояние «TASK_RUNNING».

Однако, когда 'read () 'не нужно блокировать (случай ii.) и обрабатывает запрос в пространстве ядра, я бы подумал, что поступление сигнала и его обработка будут прозрачными во многом как поступление и правильная обработкаHW прерывание будет.В частности, я бы предположил, что после доставки сигнала процесс будет временно помещен в USER-MODE для выполнения его обработчика сигнала, из которого он в конечном итоге вернется, чтобы завершить обработку прерванной операции read () (в пространстве ядра).), так что read () завершает свой курс до завершения, после чего процесс возвращается к точке сразу после вызова read () (в пространстве пользователя) со всеми доступными байтами, считанными в результате.

Но ii.Кажется, подразумевается, что read () прервана, так как данные доступны немедленно, НО он возвращает «некоторые» данные (а не все).

Это подводит меня ко второму (и последнему)вопрос

вопрос Б):

Если мое предположение по пункту А) верное, почему read () прерывается, даже если ему не нужно блокировать, потому что есть доступные данныеудовлетворить запрос немедленно?Другими словами, почему «read ()» не возобновляется после выполнения обработчика сигнала, что в итоге приводит к возвращению всех доступных данных (которые были доступны после всех)?

Ответы [ 2 ]

1 голос
/ 14 июля 2011

Когда сигнал отправляется процессу, все ядро ​​устанавливает флаг в структуре задач процесса, чтобы указать, что сигнал находится в состоянии ожидания, и активировать его, если он находится в режиме прерывистого сна (TASK_INTERRUPTIBLE).

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

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

0 голосов
/ 11 июля 2011

Драйверу устройства может потребоваться захват мьютекса перед обработкой чтения - если ожидание мьютекса прерывается сигналом, то драйвер, скорее всего, вернет EINTR как в блокирующем, так и в неблокирующем режимах, поскольку он еще не знает есть ли доступные данные. Очевидно, что он не может возвращать какие-либо данные и не должен возвращать EAGAIN, из-за чего вызывающий абонент может ошибочно предположить, что не было доступных данных, чтобы, например, вызывающий мог некоторое время спать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...