Троан Эрик В.
Шрифт:
Сигналы всегда были неотъемлемой частью Unix. Ядро использует их для извещения процессов о разнообразных событиях, включая перечисленные ниже.
• Уничтожение одного из дочерних процессов.
• Установка предупреждений устаревшим процессам.
• Изменение размеров окна терминала.
Эти сообщения имеют важное свойство: все они асинхронные. Процесс не имеет никакого контроля над тем, когда завершится один из его дочерних процессов — это может случиться в любой точке выполнения родительского процесса. Каждое из этих событий посылает сигнал процессу. При получении сигнала процесс может сделать одну из трех вещей.
• Проигнорировать сигнал.
• Позволить ядру запустить специальную часть процесса, прежде чем продолжить выполнение основной его части (это называется перехватом сигнала).
• Позволить ядру выполнить действие по умолчанию, которое зависит от конкретного полученного сигнала.
Концептуально это довольно просто. Однако история развития средств работы с сигналами видна, когда вы сравните различные интерфейсы сигналов, которые поддерживаются различными реализациями Unix. BSD, System V и System 3 поддерживают различные и несовместимые программные интерфейсы сигналов. POSIX определил стандарт, теперь поддерживаемый почти всеми версиями Unix (включая Linux), который был тогда расширен для обработки новой семантики сигнала (вроде формирования очереди сигналов) как части определения сигнала в режиме реального времени POSIX (POSIX Real Time Signal). В этой главе обсуждается исходное выполнение сигналов Unix перед объяснением основ программного интерфейса POSIX и их расширений Real Time Signal, поскольку появление многих возможностей POSIX API было мотивировано недостатками в более ранних реализациях системы сигналов.
12.1. Концепция сигналов
12.1.1. Жизненный цикл сигнала
Сигналы имеют четко определенный жизненный цикл: они создаются, сохраняются до тех пор, пока ядро не выполнит определенное действие на основе сигнала, а затем вызывают совершение этого действия. Создание сигнала называют по-разному: поднятие (raising), генерация или посылка сигнала. Обычно процесс посылает сигнал другому процессу, в то время как ядро генерирует сигналы для отправки процессу. Когда процесс посылает сигнал самому себе, говорят, что он поднимает его. Однако эти термины используются не особо согласованно.
Между временем, когда сигнал отправлен и тем, когда он вызывает какое-то действие, его называют ожидающим (pending). Это значит, что ядро знает, что сигнал должен быть обработан, но пока не имеет возможности сделать это. Как только сигнал поступает в процесс назначения, он называется доставленным. Если доставленный сигнал вызывает выполнение специального фрагмента кода (имеется в виду обработчик сигнала), то такой сигнал считается перехваченным. Есть разные способы, которыми процесс может предотвратить асинхронную доставку сигнала, но все же обработать его (например, с помощью системного вызова
Чтобы облегчить понимание, мы будем использовать эту терминологию на протяжении всей книги [52] .
12.1.2. Простые сигналы
Изначально обработка сигналов была проста. Системный вызов
52
Эта терминология распространена в большей части литературы по стандартам, включая единую спецификацию Unix (Single Unix Specification).
Здесь
Доступно множество номеров сигналов. В табл. 12.1 перечислены все сигналы, поддерживаемые в настоящее время Linux, за исключением сигналов реального времени. Они имеют символические имена, начинающиеся с
Параметр handler может иметь два специальных значения —
Функция
Все это выглядит достаточно простым, пока вы не спросите себя: что произойдет, если сигнал
53
Это механизм, используемый для утилиты