Linux сигналы
Сигналы являются программными прерываниями, которые посылаются процессу, когда случается некоторое событие. Сигналы могут возникать синхронно с ошибкой в приложении, например SIGFPE (ошибка вычислений с плавающей запятой) и SIGSEGV (ошибка адресации), но большинство сигналов является асинхронными. Сигналы могут посылаться процессу, если система обнаруживает программное событие, например, когда пользователь дает команду прервать или остановить выполнение, или получен сигнал на завершение от другого процесса. Сигналы могут прийти непосредственно от ядра ОС, когда возникает сбой аппаратных средств ЭВМ. Система определяет набор сигналов, которые могут быть отправлены процессу. В Linux применяется около 30 различных сигналов. При этом каждый сигнал имеет целочисленное значение и приводит к строго определенным действиям.
Механизм передачи сигналов состоит из следующих частей:
- установление и обозначение сигналов в форме целочисленных значений;
- маркер в строке таблицы процессов для прибывших сигналов;
- таблица с адресами функций, которые определяют реакцию на прибывающие сигналы.
Отдельные сигналы подразделяются на три класса:
- системные сигналы (ошибка аппаратуры, системная ошибка и т.д.);
- сигналы от устройств;
- сигналы, определенные пользователем.
Как только сигнал приходит, он отмечается записью в таблице процессов. Если этот сигнал предназначен для процесса, то по таблице указателей функций в структуре описания процесса выясняется, как нужно реагировать на этот сигнал. При этом номер сигнала служит индексом таблицы.
Известно три варианта реакции на сигналы:
- вызов собственной функции обработки;
- игнорирование сигнала (не работает для SIGKILL);
- использование предварительно установленной функции обработки по умолчанию.
Чтобы реагировать на разные сигналы, необходимо знать концепции их обработки. Процесс должен организовать так называемый обработчик сигнала в случае его прихода. Для этого используется функция signal
void(*signal(int signr, void(*sighandler)(int)))(int);
Такой прототип очень сложен для понимания. Следует упростить его, определив тип для функции обработки:
typedef void signalfunction(int);
После этого прототип функции примет вид:signalfunction *signal(int signr,
устанавливает номер сигнала, для которого устанавливается обработчик. В заголовочном файле <signal.h>
определены следующие сигналы (табл. 1).
Сигнал в операционных системах семейства Unix — асинхронное уведомление процесса о каком-либо событии, один из основных способов взаимодействия между процессами. Когда сигнал послан процессу, операционная система прерывает выполнение процесса, при этом, если процесс установил собственный обработчик сигнала, операционная система запускает этот обработчик, передав ему информацию о сигнале, если процесс не установил обработчика, то выполняется обработчик по умолчанию.
Названия сигналов «SIG…» являются числовыми константами (макроопределениями Си) со значениями, определяемыми в заголовочном файле signal.h
. Числовые значения сигналов могут меняться от системы к системе, хотя основная их часть имеет в разных системах одни и те же значения. Утилита kill позволяет задавать сигнал как числом, так и символьным обозначением.
Спецификация сигналов включена в стандарты POSIX.
____________________________________________________________________________
Сигналы посылаются:
- из терминала, нажатием специальных клавиш или комбинаций (например, нажатие Ctrl-C генерирует SIGINT, Ctrl-\ SIGQUIT, а Ctrl-Z SIGTSTP);
- ядром системы:при возникновении аппаратных исключений (недопустимых инструкций, нарушениях при обращении в память, системных сбоях и т. п.);
- ошибочных системных вызовах;
- для информирования о событиях ввода-вывода;
- одним процессом другому (или самому себе), с помощью системного вызова
kill()
, в том числе:из shell, утилитой/bin/kill
.
Сигналы не могут быть посланы завершившемуся процессу, находящемуся в состоянии «зомби».
Обработчик по умолчанию для большинства сигналов завершает выполнение процесса. Для альтернативной обработки всех сигналов, за исключением SIGKILL и SIGSTOP, процесс может назначить свой обработчик или игнорировать их возникновение модификацией своей сигнальной маски. Единственное исключение — процесс с pid 1 (init), который имеет право игнорировать или обрабатывать любые сигналы, включая KILL и STOP.
Процесс (или пользователь из оболочки) с реальным UID, не равным 0 (UID суперпользователя), может посылать сигналы только процессам с тем же реальным UID.
Классификация сигналов
POSIX определяет 28 сигналов, которые можно классифицировать следующим образом:
Также есть сигналы, не определённые в POSIX'е, но присутствующие в некоторых операционных системах.
- SIGEMT
- SIGINFO. Посылается процессу, когда запрос статуса (info) получен от управляющего терминала.
- SIGPWR
- SIGLOST
- SIGWINCH
- SIGSTKFLT
- SIGUNUSED
- SIGCLD
При обработке исключений и отладочных сигналов перед завершением процесс может записать в текущий каталог файл с дампом памяти процесса (англ. core image), используя который, отладчик может восстановить условия, при которых возникло данное исключение. Иногда (например, для программ, выполняемых от имени суперпользователя) дамп памяти не создаётся из соображений безопасности.
SA_SIGINFO
Обычно обработчик сигнала получает только один аргумент — номер сигнала (это позволяет использовать одну функцию-обработчик для нескольких сигналов). Если при задании обработчика сигнала (функцией sigaction()
) указать опцию SA_SIGINFO, то в обработчик будут переданы ещё два аргумента:
- указатель на структуру
siginfo_t
, включающую:битовую маску дополнительных «кодов сигнала», определяющих причину его возникновения; - идентификатор процесса (PID), пославшего сигнал;
- эффективный идентификатор пользователя (UID), от имени которого выполняется процесс (например, утилита
kill
), пославший сигнал; - адрес инструкции, в которой возникло исключение;
- и т. п.
- указатель на «машинный контекст» на момент возникновения сигнала (со «стеком сигнала» — дополнительными данными, которые помещаются в стек при вызове некоторых сигналов-исключений).
Большинство дополнительных кодов специфично для каждого сигнала. Коды, общие для всех сигналов: