Страница 135 из 253
10.2. Действия сигналов
Каждый сигнал (вскоре мы представим полный список) имеет связанное с ним действие по умолчанию. POSIX обозначает это как диспозицию (disposition) сигнала. Это то действие, которое ядро осуществляет для процесса, когда поступает определенный сигнал. Действие по умолчанию варьирует:
Завершение
Процесс завершается.
Игнорирование
Сигнал игнорируется. Программа никогда не узнает, что что-то случилось.
Снимок образа процесса
Процесс завершается, и ядро создает файл core (в текущем каталоге процесса), содержащий образ работавшей на момент поступления сигнала программы. Снимок процесса может впоследствии использоваться с отладчиком для исследования состояния программы (см. главу 15 «Отладка»).
По умолчанию системы GNU/Linux создают файлы с именем core.<i>pid</i>, где <i>pid</i> является ID завершаемого процесса. (Это можно изменить; см. sysctl(8).) Такое именование позволяет хранить в одном и том же каталоге несколько файлов core, за счет использования большего дискового пространства.[105] Традиционные системы Unix называют файл core, и это ваше дело сохранить какие-нибудь файлы core для последующего изучения, если есть шанс создания других таких же файлов в том же каталоге.
Остановка
Процесс останавливается. Впоследствии он может быть возобновлен. (Если вы использовали управление заданиями оболочки с помощью CTRL-Z, fg и bg, вы понимаете остановку процесса.)
10.3. Стандартные сигналы С: signal() и raise()
Стандарт ISO С определяет первоначальный API управления сигналами V7 и новый API для посылки сигналов. Вы должны использовать их для программ, которым придется работать на не-POSIX системах, или в случаях, когда предоставляемые ISO С API возможности являются достаточными.
10.3.1. Функция signal()
Действие сигнала изменяется с помощью функции signal(). Вы можете изменить действие на «игнорировать сигнал», «восстановить для сигнала действие системы по умолчанию» или «вызвать при появлении сигнала мою функцию с номером сигнала в качестве параметра».
Функция, которую вы предоставляете для распоряжения сигналом, называется обработчиком сигнала (или просто обработчиком), а установка ее в соответствующем месте осуществляет перехват (catch) сигнала.
Получив эти сведения, давайте перейдем к API. В заголовочном файле <signal.h> представлены определения макросов для поддерживаемых сигналов и объявления функций управления сигналами, предоставляемыми стандартом С:
#include <signal.h> /* ISO С */
void (*signal(int signum, void (*func)(int)))(int);
Это объявление для функции signal() почти невозможно прочесть. Поэтому справочная страница GNU/Linux signal(2) определяет ее таким способом:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Теперь это более вразумительно. Тип sighandler_t является указателем на функцию с возвращаемым типом void, которая принимает один целый аргумент. Это целое является номером поступающего сигнала.
Функция signal() принимает номер сигнала в качестве своего первого параметра, а указатель функции (новый обработчик) в качестве своего второго аргумента. Если последний не является указателем функции, он может быть лишь SIG_DEF, что означает «восстановить действие по умолчанию», либо SIG_IGN, что означает «игнорировать сигнал».
signal() изменяет действие для signum и возвращает предыдущее действие. (Это дает вам возможность восстановить при желании предыдущее действие.) Возвращаемое значение может равняться также SIG_ERR, что указывает на произошедшую ошибку. (Некоторые сигналы невозможно перехватить или игнорировать; предоставление для них обработчика сигнала или неверный signum создают эту ошибку.) В табл. 10.1 перечислены сигналы, доступные под GNU/Linux, их числовые значения, действия по умолчанию для каждого, формальный стандарт или современная операционная система, которые их определяют, и смысл каждого.
Таблица 10.1. Сигналы GNU/Linux