• Сигналы, которые игнорируются, продолжают игнорироваться. Особым случаем является SIGCHLD
. Если SIGCHLD
до вызова exec()
игнорировался, он может игнорироваться также и после вызова. В качестве альтернативы для него может быть восстановлено действие по умолчанию. То, что происходит на самом деле, стандартом POSIX намеренно не определяется. (Справочные страницы GNU/Linux не определяют, что делает Linux, и поскольку POSIX оставляет это не определенным, любой код, который вы пишете для использования SIGCHLD
, должен быть подготовлен для обработки любого случая.)
• Сигналы, заблокированные до вызова exec()
, остаются заблокированными и после вызова. Другими словами, новая программа наследует маску сигналов существующего процесса.
• Любые ожидающие сигналы (те, которые появились, но были заблокированы) сбрасываются. Новая программа не может их получить.
• Временной интервал, остающийся для alarm()
, сохраняется на своем месте. (Другими словами, если процесс устанавливает alarm
, а затем непосредственно вызывает exec()
, новый образ в конечном счете получит SIGALARM
. Если он сначала вызывает fork()
, родитель сохраняет установки alarm
, тогда как потомок, вызывающий exec()
, не сохраняет.
ЗАМЕЧАНИЕ. Многие, если не все. программы предполагают, что сигналы инициализированы действиями по умолчанию и что заблокированных сигналов нет. Таким образом, особенно если не вы писали программу, запускаемую с помощью exec()
, можно разблокировать перед вызовам exec()
все сигналы
10.10. Резюме
«Наша история до настоящего времени, эпизод III»
• Интерфейсы обработки сигналов развились от простых, но подверженных состояниям гонок, до сложных, но надежных. К сожалению, множественность интерфейсов затрудняет их изучение по сравнению с другими API Linux/Unix.
• У каждого сигнала есть связанное с ним действие. Действие может быть одним из следующих: игнорирование сигнала; выполнение действия системы по умолчанию или вызов предоставленного пользователем обработчика. Действие системы по умолчанию, в свою очередь, является одним из следующих: игнорирование сигнала, завершение процесса; завершение процесса с созданием его образа; остановка процесса или возобновление процесса, если он остановлен.
• signal()
и raise()
стандартизованы ISO С. signal()
управляет действиями для определенных сигналов; raise()
посылает сигнал текущему процессу. Остаются ли обработчики сигналов установленными после вызова или сбрасываются для действия по умолчанию, зависит от реализации, signal()
и raise()
являются простейшими интерфейсами, для многих приложений их достаточно.
• POSIX определяет функцию bsd_signal()
, которая подобна signal()
, но гарантирует, что обработчик остается установленным.
• Действия, происходящие после возвращения из обработчика, варьируют в зависимости от системы. Традиционные системы (V7, Solaris, возможно, и другие) восстанавливают действие сигнала по умолчанию. На этих системах прерванный системный вызов возвращает -1, устанавливая в errno
значение EINTR
. Системы BSD оставляют обработчик установленным и возвращают -1 с errno
, содержащим EINTR
, лишь в случае, когда не было перемещения данных; в противном случае, системный вызов запускается повторно.
• GNU/Linux придерживается POSIX, который похож, но не идентичен с BSD. Если не было перемещения данных, системный вызов возвращает -1/EINTR
. В противном случае он возвращает объем перемещенных данных. Поведение BSD «всегда повторный запуск» доступно через интерфейс sigaction()
, но он не является действием по умолчанию.
• Обработчики сигналов, используемые с signal()
, подвержены состояниям гонок. Внутри обработчиков сигналов должны использоваться исключительно переменные типа volatile sig_atomic_t
. (В целях упрощения в некоторых из наших примеров мы не всегда следовали этому правилу.) Таким же образом, для вызова из обработчика сигналов безопасными являются лишь функции из табл. 10.2.
• Первоначальной попыткой создания надежных сигналов был API сигналов System V Release 3 (скопированный из BSD 4.0). Не используйте его в новом коде.
• POSIX API содержит множество компонентов:
• маску сигналов процесса, перечисляющую текущие заблокированные сигналы;
• тип sigset_t
для представления масок сигналов, и функции sigfillset()
, sigemptyset()
, sigaddset()
, sigdelset()
и sigismember()
для работы с ними;
• функцию sigprocmask()
для установки и получения маски сигналов процесса,