Воспользуемся программой из листинга 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 в этой ситуации.

Перейти на страницу:

Похожие книги