В листингах 20.1 и 20.2 для вывода сообщений из обработчика сигнала мы используем функцию printf(). По причинам, которые мы обсуждаем в подразделе 21.1.2, в реальных приложениях никогда не применяются функции stdio из одного обработчика. Однако в различных примерах программ мы тем не менее будем вызывать функцию printf() из одного обработчика для обозначения факта его вызова.

Листинг 20.2. Установка одного и того же обработчика для двух разных сигналов

signals/intquit.c

#include

#include "tlpi_hdr.h"

static void

sigHandler(int sig)

{

static int count = 0;

/* НЕБЕЗОПАСНО: в этом обработчике используются функции, небезопасные

для асинхронных сигналов (printf(), exit(); см. подраздел 21.1.2) */

if (sig == SIGINT) {

count++;

printf("Caught SIGINT (%d)\n", count);

return; /* Возобновить выполнение в точке прерывания */

}

/* Должно быть SIGQUIT — распечатать сообщение и завершить процесс */

printf("Caught SIGQUIT — that\'s all, folks!\n");

exit(EXIT_SUCCESS);

}

int

main(int argc, char *argv[])

{

/* Установить один обработчик для SIGINT и SIGQUIT */

if (signal(SIGINT, sigHandler) == SIG_ERR)

errExit("signal");

if (signal(SIGQUIT, sigHandler) == SIG_ERR)

errExit("signal");

for (;;) /* Бесконечный цикл, ожидание сигналов */

pause(); /* Блокировать до перехвата сигнала */

}

signals/intquit.c

20.5. Отправка сигналов: kill()

Один процесс может отправить сигнал другому процессу с помощью системного вызова kill(), который является аналогом команды оболочки kill. (Термин kill (с англ. — «убить») был выбран, потому что действием по умолчанию для большинства сигналов, доступных в ранних версиях UNIX, было завершение процесса.)

#include

int kill(pid_t pid, int sig);

Возвращает 0 при успешном завершении и –1 при ошибке

Аргумент pid идентифицирует один или несколько процессов, в которые отправляется сигнал, задаваемый параметром sig. Четыре различных случая определяют, каким образом интерпретируется значение аргумента pid.

• Если pid больше 0, то сигнал отправляется в процесс, идентификатор которого указан в аргументе pid.

• Если pid равен 0, то сигнал отправляется во все процессы той же группы, что и вызывающий процесс, в том числе и в сам вызывающий процесс. (Стандарт SUSv3 устанавливает, что сигнал должен отправляться всем процессам группы за исключением «неуказанного набора системных процессов»; это же замечание касается всех остальных случаев.)

• Если pid меньше –1, то сигнал отправляется во все процессы группы, идентификатор которой равняется абсолютному значению аргумента pid. Такая отправка сигнала находит свое применение в управлении заданиями оболочки (см. раздел 34.7).

• Если pid равен –1, сигнал отправляется во все процессы, в которые у вызывавшего процесса есть разрешение отправлять сигналы, за исключением init (ID процесса равен 1) и вызывающего процесса. Если сигнал подается привилегированным процессом, он будет доставлен во все процессы в системе, кроме двух выше обозначенных. Сигналы, отправляемые таким образом, называются сигналами оповещения. (Стандарт SUSv3 не требует исключения вызывающего процесса из списка процессов, которые получат сигнал. В этом случае Linux следует семантике BSD.)

Если ни один из процессов не подходит под указанный в аргументе pid идентификатор, то функция kill() завершается с ошибкой и устанавливает для переменной errno значение ESRCH («Нет такого процесса»). Процессу для отправки сигнала другому требуются соответствующие разрешения. Далее перечислены правила доступа:

• Привилегированный (CAP_KILL) процесс может посылать сигналы в любой процесс.

• Процесс init (ID процесса 1), запущенный пользователем и группой root, — особый случай. В него можно посылать только те сигналы, для которых у него установлены обработчики. Это предотвращает возникновение ситуаций, когда системный администратор случайно аварийно завершает процесс init, фундаментальный для работы системы.

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

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