<<
>>

Функции поддержки сигналов

Ранее мы упоминали о нескольких вспомогательных функциях из файла signal. с. Теперь рассмотрим их подробно. Важнейшей из них является sig_proc (строка 19864), которая и отвечает за отправку сигнала.
Сначала она делает несколько проверок. Попытка послать сигнал завершившемуся или зомбированному процессу является признаком серьезной ошибки и приводит к панике в системе (строки 19889-19893). Если процесс отслеживается, то при получении сигнала он останавливается (строки 19894-19899). Если же сигнал должен игнорироваться, работа функции sig_proc завершается в строке 19902. Это действие принято по умолчанию для ряда сигналов, например для тех, которые задает стандарт POSIX, но не поддерживает MINIX 3. Если сигнал блокируется, нужно только установить соответствующий бит в битовой карте mp_sigpending процесса. Ключевое значение имеет проверка, отделяющая процессы, которым разрешено перехватывать сигнал, от тех, которым это не разрешено (строка 19910). После этого все особые случаи игнорируются, и процессы, не удостоившиеся права перехватывать сигнал, завершаются.
Единственное исключение составляют сигналы, преобразуемые в сообщения, адресованные системным службам.

Сначала мы рассмотрим обработку сигналов, которые процессу разрешено перехватывать (строки 19911-19950). Сначала формируется сообщение для ядра, некоторые части сообщения заполняются копиями информации из принадлежащей менеджеру процессов части таблицы процессов. Если ранее процесс был приостановлен сигналом sigsuspend, в сообщение включается маска сигналов, сохраненная в момент остановки, если нет, туда вставляется текущая маска (строка 19914). Дополнительно в сообщение включаются некоторые адреса из адресного пространства процесса-получателя сигнала: адрес обработчика, адрес библиотечной подпрограммы sigreturn, подлежащей вызову после завершения обработчика, и текущее значение указателя стека.

Затем выделяется место в стеке процесса. Структура, которая помещается в стек, показана на рис. 4.38. Часть sigcontext сохраняется в стеке и позднее восстанавливается из него потому, что ее значение в таблице процессов меняется при подготовке к запуску обработчика. Часть, названная sigf rame, содержит адрес возврата и данные, необходимые вызову sigreturn для восстановления состояния процесса. Адрес возврата и указатель кадра стека в действительности не используются нигде в MINIX 3. Они нужны для того, чтобы обмануть отладчик при трассировке обработчика событий.

Рис. 4.38. Чтобы подготовиться к запуску обработчика, в стек помещаются структуры sigcontext и sigframe. Регистры процессора копируются из кадра стека на момент

переключения контекста

Структура, помещаемая в стек, довольно объемна. Для нее выделяется место (строки 19923 и 19924), а затем, чтобы проверить, достаточно ли байтов в стеке, вызывается adjust. Если места не хватает, происходит переход по метке doterminate (здесь вы можете увидеть редко используемую в языке С команду goto), и процесс завершается.

При вызове adjust возможна проблема. При обсуждении реализации системного вызова Ьгк говорилось, что adjust начинает сообщать об ошибке тогда, когда стек приближается к области данных на расстояние SAFETY_BYTES. Дополнительный зазор вводится потому, что программно стек может проверяться лишь время от времени. В данном случае, вероятно, такой запас прочности излишен, так как достоверно известно, какая часть стека требуется для сигнала, а дополнительное место необходимо только обработчику, который предположительно является относительно простой функцией. Поэтому возможно, что некоторые процессы вследствие чересчур строгой проверки в adjust будут «заживо похоронены», но это все же лучше, чем наблюдать таинственные сбои в работе системы.

Таким образом, указанные проверки можно улучшить.

Если в стеке достаточно места, проверяются значения еще двух флагов. Флаг SA_NODEFER означает, что дальнейшие сигналы такого же типа должны быть блокированы на время выполнения обработчика. Флаг SA_RESETHAND — признак того, что при получении сигнала обработчик должен быть возвращен в исходное состояние. (В результате получается честная имитация устаревшего вызова signal. Хотя такое поведение обычно рассматривалось как недостаток, при поддержке устаревших функций приходится поддерживать и их недостатки.) Затем вызовом sys_sendsig ядра отправляется уведомление ядру (строка 19940). В завершение сбрасывается бит-индикатор задержанного сигнала и вызывается функция unpause, которая прерывает любой системный вызов, остановивший процесс. В следующий раз, когда процесс получит управление, начнет работу обработчик. Если по каким-либо причинам все указанные тесты закончатся неудачно, менеджер процессов вызовет сбой (строка 19949).

Упомянутое ранее исключение (преобразование сигналов в сообщения, адресованные системным службам) проверяется в строке 19951 и выполняется последующим вызовом sys_kill ядра. В результате системное задание посылает уведомление получателю сигнала. В отличие от большинства других уведомлений, уведомление системного задания помимо основной содержит дополнительную информацию — сведения об источнике и временную метку. Дополнительная информация представляет собой битовую карту сигналов, с помощью которой системный процесс, которому адресован сигнал, обнаруживает все активные сигналы. Если вызов sys_kill завершается неудачно, менеджер процессов генерирует сбой. В противном случае происходит выход из функции sig_proc (строка 19954). Если проверка в строке 19951 имеет отрицательный результат, управление передается на метку doterminate.

Теперь давайте взглянем на код завершения процесса под меткой doterminate (строка 19957). Инструкция goto и метка — самый простой механизм обработки возможных отказов при вызове adjust.

Итак, сюда передается управление, если сигнал по тем или другим причинам не может или не должен быть обработан. Возможно, перехваченный сигнал необходимо проигнорировать; в этом случае sig_proc просто завершает работу. В противном случае завершиться должен процесс. Единственный вопрос состоит в том, нужно ли генерировать при этом дамп памяти. Наконец, процесс завершается вызовом pm_exit (строка 19967) так, как будто он делает это сам.

В функции check_sig (строка 19973) менеджер процессов проверяет, может ли быть послан сигнал. Например:

kill (0,sig);

Этот вызов означает, что указанный сигнал должен быть отправлен всем процессам в текущей группе (то есть всем процессам, запущенным с того же терминала). Сигналы, исходящие от ядра и системного вызова reboot, также могут затрагивать несколько процессов. По этой причине check_sig в цикле перебирает все процессы из таблицы процессов, выбирая из них потенциальных получателей (строки 19996-20026). В цикле содержится много тестов, и только если все они пройдены, при помощи sig_proc отправляется сигнал (строка 20023).

Еще одна функция, которая несколько раз вызывается в рассмотренном нами коде, называется check_pending (строка 20036). Она перебирает все биты в битовой карте mp_sigpending процесса, сверяясь с битовыми картами с помощью функций do_sigmask, do_sigretrun и do_sigsuspend, и смотрит, не была ли снята блокировка с одного из задержанных сигналов. Обнаружив первый такой сигнал, она отправляет его. Так как все обработчики событий со временем вызывают функцию do_sigreturn, все разблокированные активные сигналы в конце концов доставляются.

Процедура unpause (строка 20065) необходима для отправки сигналов процессам, приостановленным на одном из вызовов pause, wait, read, write или sigsuspend. Выяснить, обусловлена ли остановка вызовом pause, wait или sigsuspend, можно, сверившись с таблицей процессов менеджера процессов. Если выясняется, что ни один из этих вызовов не является причиной остановки, запрос передается файловой системе, которая при помощи собственной функции do_ unpause проверяет, был ли процесс приостановлен для чтения или записи.

В любом случае результат одинаков: незаконченный вызов завершается с ошибкой, а процесс вновь запускается и может обработать сигнал.

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

Код записи в файл прост. Здесь снова возможна проблема, упомянутая в предыдущем разделе, но теперь в несколько иной форме. Чтобы гарантировать, что записываемый в дамп сегмент стека содержит самую последнюю информацию, вызывается функция adjust (строка 20010). Из-за проверки границы безопасности этот вызов может «провалиться». Правда, дамп записывается в любом случае, независимо от успеха вызова, но информация о стеке может оказаться неправильной.

<< | >>
Источник: Э. ТАНЕНБАУМ, А. ВУДХАЛЛ. ОПЕРАЦИОННЫЕ СИСТЕМЫ Разработка и реализация 3-е издание. 2007

Еще по теме Функции поддержки сигналов:

  1. Функции журналистики. Понятие функцию Многообразие социальных и информационных потребностей общества – объективная основа функций журналистики.
  2. Ловите сигналы
  3. Понимание невербальных сигналов в деловой ситуации.
  4. РАБОТА С ДАЛЬНИМИ СИГНАЛАМИ. ПВБ
  5. СИМОРОНСКИЕ ПРИНЦИПЫ РАБОТЫ С СИГНАЛАМИ
  6. Предложение №40 Работай с сигналами страха Рецепт освобождения от зависимостей
  7. “Не язык — функция поэта, а поэт — функция языка”
  8. 5.2.3. Группа поддержки
  9. СИГНАЛЫ, ПРЕДУПРЕЖДАЮЩИЕ МУЖЧИНУ О ТОМ, ЧТО ЖЕНЩИНА, ВОЗМОЖНО ОПУСКАЕТСЯ В КОЛОДЕЦ ИЛИ ЧТО ЕЙ ОСОБЕННО НУЖНА ЕГО ЛЮБОВЬ
  10. Моральная поддержка окружения
  11. Поддержка
  12. Поддержка
  13. ПРАВИЛО ПОДДЕРЖКИ МЕНЬШИНСТВА
  14. ГЛАВА 12 КАК ПОПРОСИТЬ О ПОДДЕРЖКЕ, ЧТОБЫ ПОЛУЧИТЬ ЕЕ
  15. ¦ Поддержка со стороны единомышленников.
  16. О ПОДДЕРЖКЕ В ТРУДНЫЕ МОМЕНТЫ ЖИЗНИ
  17. Почему у мужчин обостренная реакция на просьбы о поддержке