Caught SIGTSTP
[1]+ Stopped./handling_SIGTSTP
$ fg
./handling_SIGTSTP
Exiting SIGTSTP handler
Main
В программах, которые управляют экраном (таких как vi), вызов printf() внутри обработчика сигнала из листинга 34.6 был бы заменен кодом, переключающим режим терминала и перерисовывающим его окно, как было отмечено выше. Чтобы избежать использования функций, которые не рассчитаны на безопасную работу с асинхронными сигналами (см. подраздел 21.1.2), обработчик должен установить флаг, информируя главную программу о необходимости перерисовать экран.
Стоит отметить, что обработчик SIGTSTP может прервать работу некоторых блокирующих системных вызовов (описанных в разделе 21.5). В программном выводе, приведенном выше, этот момент проиллюстрирован тем, что после прерывания вызова pause() главная программа выводит сообщение Main.
Листинг 34.6. Обработка сигнала SIGTSTP
pgsjc/handling_SIGTSTP.c
#include
#include "tlpi_hdr.h"
static void /* Обработчик для сигнала SIGTSTP */
tstpHandler(int sig)
{
sigset_t tstpMask, prevMask;
int savedErrno;
struct sigaction sa;
savedErrno = errno; /* Если мы изменим здесь 'errno' */
printf("Caught SIGTSTP\n"); /* НЕБЕЗОПАСНО (см. подраздел 21.1.2) */
if (signal(SIGTSTP, SIG_DFL) == SIG_ERR)
errExit("signal"); /* Используем действие по умолчанию */
raise(SIGTSTP); /* Генерируем еще один сигнал SIGTSTP */
/* Разблокируем SIGTSTP; ожидающий сигнал SIGTSTP сразу приостанавливает программу */
sigemptyset(&tstpMask);
sigaddset(&tstpMask, SIGTSTP);
if (sigprocmask(SIG_UNBLOCK, &tstpMask, &prevMask) == –1)
errExit("sigprocmask");
/* Выполнение продолжается после получения SIGCONT */
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == –1)
errExit("sigprocmask"); /* Еще раз блокируем SIGTSTP */
sigemptyset(&sa.sa_mask); /* Снова устанавливаем обработчик */
sa.sa_flags = SA_RESTART;
sa.sa_handler = tstpHandler;
if (sigaction(SIGTSTP, &sa, NULL) == –1)
errExit("sigaction");
printf("Exiting SIGTSTP handler\n");
errno = savedErrno;
}
int
main(int argc, char *argv[])
{
struct sigaction sa;
/* Устанавливаем обработчик для сигнала SIGTSTP, только если он не игнорируется */
if (sigaction(SIGTSTP, NULL, &sa) == –1)
errExit("sigaction");
if (sa.sa_handler!= SIG_IGN) {
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = tstpHandler;
if (sigaction(SIGTSTP, &sa, NULL) == –1)
errExit("sigaction");
}
for (;;) { /* Ждем сигнала */
pause();
printf("Main\n");
}
}
pgsjc/handling_SIGTSTP.c
Работа с игнорируемыми сигналами, сгенерированными терминалом или предназначенными для управления заданиями
Программа, представленная в листинге 34.6, устанавливает обработчик для сигнала SIGTSTP, только если тот не игнорируется. Это частный случай более общего правила, согласно которому приложения должны обрабатывать сигналы, сгенерированные терминалом или предназначенные для управления заданиями, только если они не были проигнорированы ранее. В случае с сигналами для управления заданиями (SIGTSTP, SIGTTIN и SIGTTOU) это помогает избежать их обработки, если программа была запущена из командной оболочки, которая не поддерживает эту возможность (такой как bash). В таких оболочках действия этих сигналов имеют значение SIG_IGN; значение SIG_DFL устанавливается только в том случае, если командная оболочка поддерживает управление заданиями.
Похожая ситуация и с другими сигналами, которые могут быть сгенерированы терминалом: SIGINT, SIGQUIT и SIGHUP. В случае с первыми двумя причина заключается в том, что при выполнении программы в фоновом режиме в рамках командной оболочки, не поддерживающей управление заданиями, итоговый процесс не размещается в отдельной группе. Вместо этого он остается в одной группе с оболочкой, которая перед выполнением программы делает действия сигналов SIGINT и SIGQUIT игнорируемыми. Благодаря этому процесс не завершится, если пользователь нажмет в терминале сочетания клавиш для
Сигнал SIGHUP игнорируется, если программа выполняется посредством утилиты nohup(1). Это защищает ее от преждевременного завершения в случае зависания терминала. Таким образом, приложение не должно пытаться изменить действие этого сигнала, если он игнорируется.