Справочное руководство по библиотеке GNU C имеет целую главу, объясняющую все об обработке сигналов.
Вы всегда получаете предварительно установленный обработчик сигнала (указатель функции), когда устанавливаете свой собственный обработчик(см. справочные страницы для signal()
или sigaction()
).
previous_handler = signal(SIGINT, myhandler);
Общее правило: вы всегда можете вернуться к предыдущему обработчику и raise()
повторить сигнал.
void myhandler(int sig) {
/* own stuff .. */
signal(sig, previous_handler);
raise(sig);
/* when it returns here .. set our signal handler again */
signal(sig, myhandler);
}
Существует один недостаток общего правила: аппаратные исключения, которые сопоставляются с сигналами, обычно присваиваются определенной инструкции, которая вызвала исключение.Таким образом, когда вы снова подаете сигнал, соответствующая инструкция не совпадает с исходной.Это может, но не должно наносить вред другим обработчикам сигналов.
Еще один недостаток заключается в том, что каждый повышенный сигнал вызывает много времени обработки.Для предотвращения чрезмерного использования raise()
вы можете использовать следующие альтернативы:
В случае SIG_DFL
указатель функции указывает на адрес 0
(который, очевидно, не является действительным адресом),Таким образом, вам необходимо сбросить обработчик и raise()
сигнал снова.
if (previous_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
raise(sig);
signal(sig, myhandler);
}
SIG_IGN
имеет значение 1
(также недействительный адрес).Здесь вы можете просто вернуться (ничего не делать).
else if (previous_handler == SIG_IGN)
{
return;
}
В противном случае (ни SIG_IGN
, ни SIG_DFL
) вы получили действительный указатель на функцию, и вы можете напрямую вызвать обработчик,
else
{
previous_handler(sig);
}
Конечно, вы также должны учитывать различные API (см. Справочные страницы для signal()
и sigaction()
).