void handler(int signum, siginfo_t *siginfo, void *context);
Приложение должно указать ядру на необходимость передачи полной информации о контексте, устанавливая флаг SA_SIGINFO
члена sa_mask
структуры struct sigaction
, применяемой для регистрации обработчика сигнала. Член sa_handler
также не используется, потому что он является указателем на функцию с другим прототипом. Вместо этого новый член, sa_sigaction
, указывает на обработчик сигнала с правильным прототипом. Чтобы снизить потребление памяти, sa_handler
и sa_sigaction
разрешено использовать один и тот же участок памяти, поэтому только один из двух должен применяться в одно и то же время. Чтобы сделать это прозрачным, библиотека С определяет struct sigaction
следующим образом.
#include
struct sigaction {
union {
__sighandler_t sa_handler;
__sigaction_t sa_sigaction;
} __sigaction_handler;
sigset_t sa_mask;
unsigned long sa_flags;
};
#define sa_handler __sigaction_handler.sa_handler
#define sa_sigaction __sigaction_handler.sa_sigaction
Использование представленной комбинации объединений и макросов позволяет этим двум членам разделять одну и ту же память без необходимости усложнения с точки зрения приложений.
Структура siginfo_t
содержит информацию о том, где и почему был сгенерирован сигнал. Всем сигналам доступны два члена: sa_signo
и si_code
. Какие другие члены доступны — зависит от конкретного сигнала, и эти члены разделяют память подобно тому, как это делают члены sa_handler
и sa_sigaction
структуры struct sigaction
. Член sa_signo
содержит номер доставленного сигнала и всегда равен значению первого параметра, переданного обработчику сигнала, в то время как si_code
указывает, почему сигнал был сгенерирован, и изменяется в зависимости от номера сигнала. Для большинства сигналов он может принимать перечисленные ниже значения. [70] Существует гораздо больше значений si_code , нежели мы обсуждаем здесь, и эти значения имеют отношение к асинхронному вводу-выводу, очередям сообщений и таймерам реального времени, что выходит за границы тем, обсуждаемых в книге.
SI_USER
Приложение пространства пользователя вызвало kill()
для отправки сигнала. Примечание. Функция sigsend()
, включенная в Linux для совместимости с некоторыми системами Unix, также выдает SI_USER
.
SI_QUEUE
Приложение пространства пользователя вызвало sigqueue()
для от правки сигнала, что обсуждается в самом конце этой главы.
SI_TKILL
Приложение пространства пользователя вызвало tkill()
. В то время как ядро Linux использует SI_TKILL
, его значение не специфицировано в текущей версии библиотеки С.
Если вам нужно проверить SI_TKILL
, используйте следующий сегмент кода для определения этого значения:
#ifndef SI_TKILL
#define SI_TKILL -6
#endif
SI_TKILL
не специфицирован ни в каком стандарте (хотя допускается ими), поэтому его следует применять осторожно в переносимых программах.
SI_KERNEL
Сигнал сгенерирован ядром.
Когда SIGILL
, SIGFPE
, SIGSEGV
, SIGBUS
и SIGCHLD
посылаются ядром, то si_ code
вместо si_kernel
принимает значения, перечисленные в табл. 12.3 [71] Он также принимает специальное значение SIGTRAP , которое используется отладчиками, и SIGPOLL , применяемое механизмом ненадежного асинхронного ввода-вывода. Ни один из них не описан в настоящей книге, поэтому подробности об этих сигналах не включены в табл. 12.3.
.
Таблица 12.3. Значения si_code
для специальных сигналов
Сигнал |
si_code |
Описание |
SIGILL |
ILL_ILLOPC |
Неправильный код операции (opcode). |
|
ILL_ILLOPC |
Неправильный операнд. |
|
ILL_ILLOPC |
Неправильный режим адресации. |
|
ILL_ILLOPC |
Неправильная ловушка (trap). |
|
ILL_ILLOPC |
Привилегированный код операции. |
|
ILL_ILLOPC |
Привилегированный регистр. |
|
ILL_ILLOPC |
Внутренняя ошибка стека. |
|
ILL_ILLOPC |
Ошибка сопроцессора. |
SIGFPE |
FPE_INTDIV |
Деление целого на ноль. |
|
FPE_INTOVF |
Переполнение целого. |
|
FPE_FLTDIV |
Деление числа с плавающей точкой на ноль. |
|
FPE_FLTOVF |
Переполнение числа с плавающей точкой. |
|
FPE_FLTUND |
Потеря значимости числа с плавающей точкой. |
|
FPE_FLTRES |
Неточный результат числа с плавающей точкой. |
|
FPE_FLTINV |
Неверная операция с плавающей точкой. |
|
FPE_FLTSUB |
Число с плавающей точкой вне диапазона. |
SIGSEGV |
SEGV_MAPPER |
Адрес не отображается на объект. |
|
SEGV_ACCERR |
Неверные права доступа для адреса. |
SIGBUS |
BUS_ADRALN |
Неверное выравнивание адреса. |
|
BUS_ADRERR |
Несуществующий физический адрес. |
|
BUS_OBJERR |
Специфичный для объекта сбой оборудования. |
SIGCHLD |
CLD_EXITED |
Дочерний процесс завершен. |
|
CLD_KILLED |
Дочерний процесс уничтожен. |
|
CLD_DUMPED |
Дочерний процесс уничтожен с выводом дампа памяти в файл. |
|
CLD_TRAPPED |
Дочерний процесс достиг точки останова. |
|
CLD_STOPPED |
Дочерний процесс приостановлен. |
Чтобы помочь прояснить разные значения, которые может принимать si_code
, рассмотрим пример, в котором SIGCHLD
генерируется четырьмя разными способами: kill()
, sigqueue()
, raise
() (использует системный вызов tkill()
) и созданием дочернего процесса, который немедленно прерывается.
Читать дальше