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 и справочной странице 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 *context, является расширенной возможностью, которая больше не обсуждается в данной книге.
Наконец, чтобы увидеть 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
2095
2096 raise(sig); /* Повторно послать сигнал */
2097 }
Вот код в main(), который помещает обработчик на свое место:
2214 #ifdef SA_NOCLDSTOP /* На системе POSIX... */
2215 {