Воспользуемся программой из листинга 34.3, чтобы показать, что командная оболочка, получив сигнал SIGHUP, передает его всем заданиям, которые она создала. Главная цель этой программы — создать дочерний процесс, после чего приостановить работу родителя и потомка, чтобы перехватить сигнал SIGHUP и, если это удалось, вывести соответствующее сообщение. Если указать для программы необязательный аргумент командной строки (который может представлять собой набор символов), потомок разместится в другой группе процессов (в рамках той же сессии). Это позволит показать, что командная оболочка не передает сигнал SIGHUP группам процессов, которые она не создавала, даже если они находятся внутри одной сессии (поскольку завершающий цикл for является бесконечным, мы используем вызов alarm(), чтобы установить таймер для доставки сигнала SIGALRM; появление этого сигнала при отсутствии обработчика всегда приводит к завершению процесса, если он не был завершен по какой-то другой причине).
Листинг 34.3. Перехватывание сигнала SIGHUP
pgsjc/catch_SIGHUP.c
#define _XOPEN_SOURCE 500
#include
#include
#include "tlpi_hdr.h"
static void
handler(int sig)
{
}
int
main(int argc, char *argv[])
{
pid_t childPid;
struct sigaction sa;
setbuf(stdout, NULL); /* Отключаем буферизацию стандартного вывода */
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = handler;
if (sigaction(SIGHUP, &sa, NULL) == –1)
errExit("sigaction");
childPid = fork();
if (childPid == –1)
errExit("fork");
if (childPid == 0 && argc > 1)
if (setpgid(0, 0) == –1)
/* Перемещаемся в новую группу процессов */
errExit("setpgid");
printf("PID=%ld; PPID=%ld; PGID=%ld; SID=%ld\n", (long) getpid(),
(long) getppid(), (long) getpgrp(), (long) getsid(0));
alarm(60); /* Необработанный сигнал SIGALRM всегда приводит
к завершению процесса, если он не был завершен
по другой причине */
for(;;) { /* Ждем появления сигнала */
pause();
printf("%ld: caught SIGHUP\n", (long) getpid());
}
}
pgsjc/catch_SIGHUP.c
Представим, что мы ввели следующие команды, чтобы запустить два экземпляра программы из листинга 34.3, и затем закрыли окно терминала:
$ echo $$
5533
$ ./catch_SIGHUP > samegroup.log 2>&1 &
$ ./catch_SIGHUP x > diffgroup.log 2>&1
Первая команда приводит к созданию двух процессов, которые остаются в группе, созданной командной оболочкой. Вторая команда создает дочерний процесс, который помещается в отдельную группу.
Просмотрев файл samegroup.log, мы увидим следующий вывод, указывающий на то, что оба участника группы процессов получили сигналы от командной оболочки:
$ cat samegroup.log
PID=5612; PPID=5611; PGID=5611; SID=5533
PID=5611; PPID=5533; PGID=5611; SID=5533
5611: caught SIGHUP
5612: caught SIGHUP
Если взглянуть на содержимое файла diffgroup.log, станет ясно, что оболочка, получив сигнал SIGHUP, не отправила его группе процессов, которую она не создавала:
$ cat diffgroup.log
PID=5614; PPID=5613; PGID=5614; SID=5533
PID=5613; PPID=5533; PGID=5613; SID=5533
5613: caught SIGHUP
34.6.2. Сигнал SIGHUP и завершение контролирующего процесса
Если сигнал SIGHUP, передающийся контролирующему процессу в результате отключения терминала, приводит к завершению этого процесса, он отправляется всем участникам активной группы (см. раздел 25.2). Это является следствием завершения контролирующего процесса и не связано непосредственно с сигналом SIGHUP (так как он передается вне зависимости от причины завершения).
В Linux вслед за SIGHUP передается сигнал SIGCONT; благодаря этому группа процессов может возобновить свою работу, если ранее она была приостановлена по сигналу. Однако такое поведение не предусмотрено стандартом SUSv3, и большинство других UNIX-систем не отправляют сигнал SIGCONT в этой ситуации.