Механизмы обработки сигналов развились с течением времени. Как бывает почти со всеми такими механизмами, стандартизованы и доступны как первоначальные, так и более новые API. Однако, из фундаментальных API обработка сигналов обнаруживает, возможно, самые широкие изменения; имеется множество возможностей обработки, чтобы преуспеть в использовании наиболее подходящего API. В результате, возможно, это самая трудная глава в книге. Мы сделаем всевозможное, чтобы сделать изложение более ясным, но если вы проработаете эту главу более тщательно, чем обычно, это поможет.
В отличие от большинства глав в данной книге, наше представление здесь историческое, связанное с освещением развития API, sigaction()
поддерживает все те возможности, которые поддерживает.
10.2. Действия сигналов
Каждый сигнал (вскоре мы представим полный список) имеет связанное с ним
Процесс завершается.
Сигнал игнорируется. Программа никогда не узнает, что что-то случилось.
Процесс завершается, и ядро создает файл core (в текущем каталоге процесса), содержащий образ работавшей на момент поступления сигнала программы. Снимок процесса может впоследствии использоваться с отладчиком для исследования состояния программы (см. главу 15 «Отладка»).
По умолчанию системы GNU/Linux создают файлы с именем core.
, где
является ID завершаемого процесса. (Это можно изменить; см. 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()
. Вы можете изменить действие на «игнорировать сигнал», «восстановить для сигнала действие системы по умолчанию» или «вызвать при появлении сигнала мою функцию с номером сигнала в качестве параметра».
Функция, которую вы предоставляете для распоряжения сигналом, называется
Получив эти сведения, давайте перейдем к API. В заголовочном файле
представлены определения макросов для поддерживаемых сигналов и объявления функций управления сигналами, предоставляемыми стандартом С:
#include
void (*signal(int signum, void (*func)(int)))(int);
Это объявление для функции signal() почти невозможно прочесть. Поэтому справочная страница GNU/Linux
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Теперь это более вразумительно. Тип sighandler_t
является указателем на функцию с возвращаемым типом void
, которая принимает один целый аргумент. Это целое является номером поступающего сигнала.
Функция signal()
принимает номер сигнала в качестве своего первого параметра, а указатель функции (новый обработчик) в качестве своего второго аргумента. Если последний не является указателем функции, он может быть лишь SIG_DEF,
что означает «восстановить действие по умолчанию», либо SIG_IGN
, что означает «игнорировать сигнал».