Надежный интерфейс сигналов
Мы рассмотрели подробно возбуждение и перехват сигналов с помощью signalи родственных функций, поскольку они очень часто применяются в старых UNIX-программах. Тем не менее, стандарты X/Open и спецификации UNIX рекомендуют более современный программный интерфейс для сигналов sigaction, который более надежен.
#include
int sigaction
Структура sigaction, применяемая для определения действий, предпринимаемых при получении сигнала, заданного в аргументе sig, определена в файле signal.h и как минимум включает следующие элементы:
void (*)(int)sa_handler /* функция, SIG_DFL или SIG_IGN */
sigset_t sa_mask /* сигналы, заблокированные для sa_handler */
int sa_flags /* модификаторы действий сигнала */
Функция sigactionзадает действие, связанное с сигналом sig. Если oactне null, sigactionзаписывает предыдущее действие для сигнала в указанное oactместо. Если actравен null, это все, что делает функция sigaction. Если указатель actне null, задается действие для указанного сигнала.
Как и функция signal, sigactionвозвращает 0 в случае успешного выполнения и -1 в случае ошибки. Переменная errnoполучит значение EINVAL, если заданный сигнал некорректен или была предпринята попытка захватить или проигнорировать сигнал, который нельзя захватывать или игнорировать.
В структуре sigaction, на которую указывает аргумент act, sa_handler— это указатель на функцию, вызываемую при получении сигнала sig. Она очень похожа на функцию func, которая, как вы видели раньше, передавалась функции signal. Вы можете применять специальные значения SIG_IGNи SIG_DFLв поле sa_handlerдля обозначения того, что сигнал должен игнорироваться или должно быть восстановлено действие по умолчанию, соответственно.
Поле sa_maskописывает множество сигналов, которые будут добавлены в маску сигналов процесса перед вызовом функции sa_handler. Это множество сигналов, которые блокируются и не должны доставляться процессу. Такое поведение мешает возникновению ситуации, описанной ранее, в которой сигнал был получен до того, как его обработчик дошел до завершения. Применение поля sa_maskможет устранить это состояние гонок.
Однако сигналы, захватываемые обработчиками, заданными в структуре sigaction, по умолчанию не восстанавливаются, и нужно задать в поле sa_flagsзначение SA_RESETHAND, если хотите добиться поведения, виденного вами раньше при обсуждении функции signal. Прежде чем обсуждать подробнее sigaction, давайте перепишем программу ctrlc.c, применяя sigactionвместо функции signal(упражнение 11.9).
Упражнение 11.9. Функция sigaction
Внесите приведенные далее изменения, так чтобы сигнал SIGINTперехватывался sigaction. Назовите новую программу ctrlc2.c.
#include
#include
#include
void ouch(int sig) {
printf("OUCH! - I got signal %d\n", sig);
}
int main() {
struct sigaction act;
act.sa_handler = ouch;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, 0);
while (1) {
printf("Hello World!\n");
sleep(1);
}
}
Когда вы выполните эту версию программы, то всегда будете получать сообщение при нажатии комбинации клавиш +, поскольку SIGINTобрабатывается неоднократно функцией sigaction. Для завершения программы следует нажать комбинацию клавиш +<\>, которая генерирует по умолчанию сигнал SIIGQUIT.
$ ./ctrlc2
Hello World!
Hello World!
Hello World!
^C
OUCH! - I got signal 2
Hello World!
Hello World!
^C
OUCH! - I got signal 2
Hello World!
Hello World!
^\
Quit
$
Как это работает
Программа вместо функции signalвызывает sigactionдля задания функции ouchкак обработчика сигнала, возникающего при нажатии комбинации клавиш + ( SIGINT). Прежде всего, она должна определить структуру sigaction, содержащую обработчик, маску сигналов и флаги, В данном случае вам не нужны никакие флаги, и создается пустая маска сигналов с помощью новой функции sigemptyset.
Читать дальше