Linux программирование в примерах
20952096 raise(sig); /* Повторно послать сигнал */2097 }Вот код в
, который помещает обработчик на свое место:main()2214 #ifdef SA_NOCLDSTOP /* На системе POSIX... */2215 {2216 unsigned i;2217 sigemptyset(&caught_signals);2218 for (i = 0; i < nsigs; i++) /* - Блокировать все сигналы */2219 sigaddset(&caught_signals, sigs[i]);2220 newact.sa_handler = sighandler; /* - Функция обработки сигнала */2221 newact.sa_mask = caught_signals; /* - Установить для обработчика маску сигналов процесса */2222 newact.sa_flags =0; /* - Особых флагов нет */2223 }2224 #endif22252226 {2227 unsigned i;2228 for (i = 0; i < nsigs; i++) /* Для всех сигналов... */2229 {2230 int sig = sigs[i];2231 #ifdef SA_NOCLDSTOP2232 sigaction(sig, NULL, &oldact); /* - Получить старый обработчик */2233 if (oldact.sa_handler != SIG_IGN) /* - Если этот сигнал не игнорируется */2234 sigaction(sig, &newact, NULL); /* - Установить наш обработчик */2235 #else2236 if (signal(sig, SIG_IGN) != SIG_IGN)2237 signal(sig, sighandler); /* - Та же логика со старым API */2238 #endif2239 }2240 }Мы заметили, что строки 2216–2219 и 2221 могут быть замещены одним вызовом:
;sigfillset(&newact.sa_mask)Мы не знаем, почему код написан именно таким способом.
Интерес представляют также строки 2233–2234 и 2236–2237, которые показывают правильный способ проверки того, игнорируется ли сигнал, и для установки обработчика лишь в том случае, если сигнал не игнорируется.
ЗАМЕЧАНИЕ. Функции API
иsigaction()не должны использоваться вместе для одного и того же сигнала. Хотя POSIX идет на большие длинноты, чтобы сначала сделать возможным использованиеsignal(), получитьsignal(), представляющую диспозициюstruct sigaction, и восстановить ее, все равно это плохая мысль. Код будет гораздо проще читать, писать и понимать, если вы используете одну функцию или другую взаимоисключающим образамsignal()10.6.5. Извлечение ожидающих сигналов:
sigpending()Описанный ранее системный вызов
позволяет получить набор ожидающих сигналов, т.е тех сигналов, которые появились, но еще не доставлены из-за блокировки:sigpending()#include <signal.h> /* POSIX */int sigpending(sigset_t *set);Помимо разблокировки ожидающих сигналов, чтобы они могли быть доставлены, вы можете решить их игнорировать. Установка действия сигнала
вызывает сбрасывание сигнала (даже если он был заблокирован). Сходным образом для тех сигналов, действием по умолчанию для которых является их игнорирование, установка действия вSIG_IGNтакже вызывает сбрасывание таких ожидающих сигналов.SIG_DFL10.6.6. Создание возможности для прерывания функций:
siginterrupt()Чтобы сделать определенную функцию прерываемой или повторно запускаемой в зависимости от значения второго аргумента, в качестве удобного средства может использоваться функция
. Объявление следующее:siginterrupt()#include <signal.h> /* XSI */int siginterrupt(int sig, int flag);В соответствии со стандартом POSIX поведение
эквивалентно следующему коду:siginterrupt()int siginterrupt(int sig, int flag) {int ret;struct sigaction act;(void)sigaction(sig, NULL, &act); /* Получить старые установки */if (flag) /* Если flag равен true... */act.sa_flags &= ~SA_RESTART; /* Запретить повторный запуск */else /* В противном случае... */act.sa_flags |= SA_RESTART; /* Разрешить повторный запуск */ret = sigaction(sig, &act, NULL);/* Поместить новые установки на место */return ret; /* Вернуть результат */}В случае успеха возвращаемое значение равно 0 и -1 при ошибке.
10.6.7. Передача сигналов:
иkill()killpg()Традиционная функция Unix для передачи сигналов называется
. Имя несколько неправильное; все, что она делает — отправляет сигнал. (Результатом этого часто является завершение получателя сигнала, но это не обязательно верно. Однако, теперь слишком поздно менять имя.) Функцияkill()посылает сигнал определенной группе процессов. Объявления следующие:killpg()#include <sys/types.h> /* POSIX */#include <signal.h>int kill(pid_t pid, int sig);int killpg(int pgrp, int sig); /* XSI */Аргумент
является либо именем сигнала, либо 0. В последнем случае сигнал не посылается, но ядро все равно осуществляет проверку ошибок. В частности, это правильный способ проверки существования данного процесса или группы, а также проверки того, что у вас есть разрешение на передачу сигналов процессу или группе процессовsigвозвращает 0 в случае успеха и -1 при ошибке;kill()указывает на проблему.errno