Когда в
act->sa_flags
установлен флаг
SA_SIGINFO
, поле
act->sa_sigaction
является указателем на функцию, объявленную следующим образом:
void action_handler(int sig, siginfo_t *info, void *context) {
/* Здесь тело обработчика */
}
Структура
siginfo
_t предоставляет изобилие сведений о сигнале:
/* Определение POSIX 2001. Действительное содержание может на разных системах быть разным. */
typedef struct {
int si_signo; /* номер сигнала */
int si_errno; /* значение <errno.h> при ошибке */
int si_code; /* код сигнала; см. текст */
pid_t si_pid; /* ID процесса, пославшего сигнал */
uid_t si_uid; /* настоящий UID посылающего процесса */
void *si_addr; /* адрес вызвавшей ошибку инструкции */
int si_status; /* значение завершения, может включать death-by-signal */
long si_band; /* связывающее событие для SIGPOLL/SIGIO */
union sigval si_value; /* значение сигнала (расширенное) */
} siginfo_t;
Поля
si_signo
,
si_code
и
si_value
доступны для всех сигналов. Другие поля могут быть членами объединения, поэтому должны использоваться лишь для тех сигналов, для которых они определены. В структуре
siginfo_t
могут быть также и другие поля.
Почти все поля предназначены для расширенного использования. Все подробности содержатся в стандарте POSIX и справочной странице sigaction(2). Однако, мы можем описать простое использование поля
si_code
.
Для
SIGBUS
,
SIGCHLD
,
SIGFPE
,
SIGILL
,
SIGPOLL
,
SIGSEGV
и
SIGTRAP
поле si_code может принимать любое из набора предопределенных значений, специфичных для каждого сигнала, указывая на причину появления сигнала. Откровенно говоря, детали несколько чрезмерны; повседневному коду на самом деле нет необходимости иметь с ними дела (хотя позже мы рассмотрим значения для
SIGCHLD
). Для всех остальных сигналов член
si_code
имеет одно из значений из табл. 10.4.
Таблица 10.4. Значения происхождения сигнала для
si_code
Значение | Только GLIBC | Смысл |
SI_ASYNCIO
| | Асинхронный ввод/вывод завершен (расширенный). |
SI_KERNEL
| √ | Сигнал послан ядром. |
SI_MESGQ
| | Состояние очереди сообщений изменилось (расширенный.) |
SI_QUEUE
| | Сигнал послан из sigqueue() (расширенный). |
SI_SIGIO
| √ | SIGIO поставлен в очередь (расширенный). |
SI_TIMER
| | Время таймера истекло |
SI_USER
| | Сигнал послан функцией kill() . raise() и abort() также могут его вызвать, но это не обязательно. |
В особенности полезно значение
SI_USER
; оно позволяет обработчику сигнала сообщить, был ли сигнал послан функциями
raise()
или
kill()
(описываются далее). Вы можете использовать эту информацию, чтобы избежать повторного вызова
raise()
или
kill()
.
Третий аргумент обработчика сигнала с тремя аргументами,
void *contex
t, является расширенной возможностью, которая больше не обсуждается в данной книге.
Наконец, чтобы увидеть
sigaction()
в действии, исследуйте полный исходный код обработчика сигнала для
sort.c
:
2074 static void
2075 sighandler(int sig)
2076 {
2077 #ifndef SA_NOCLDSTOP /* В системе старого стиля... */
2078 signal(sig, SIG_IGN); /* - для игнорирования sig используйте signal()*/
2079 #endif - /* В противном случае sig автоматически блокируется */
2080
2081 cleanup(); /* Запуск кода очистки */
2082
2083 #ifdef SA_NOCLDSTOP /* В системе в стиле POSIX... */
2084 {
2085 struct sigaction sigact;
2086
2087 sigact.sa_handler = SIG_DFL; /* - Установить действие по умолчанию */
2088 sigemptyset(&sigact.sa_mask); /* - Нет дополнительных сигналов для блокирования */
2089 sigact.sa_flags = 0; /* - Специальные действия не предпринимаются */
2090 sigaction(sig, &sigact, NULL); /* - Поместить на место */
2091 }
2092 #else /* На системе в старом стиле... */
2093 signal(sig, SIG_DFL); /* - Установить действие по умолчанию */
2094 #endif