В листингах 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
Один процесс может отправить сигнал другому процессу с помощью системного вызова kill(), который является аналогом команды оболочки kill. (Термин
#include
int kill(pid_t
Возвращает 0 при успешном завершении и –1 при ошибке
Аргумент pid идентифицирует один или несколько процессов, в которые отправляется сигнал, задаваемый параметром sig. Четыре различных случая определяют, каким образом интерпретируется значение аргумента pid.
• Если pid больше 0, то сигнал отправляется в процесс, идентификатор которого указан в аргументе pid.
• Если pid равен 0, то сигнал отправляется во все процессы той же группы, что и вызывающий процесс, в том числе и в сам вызывающий процесс. (Стандарт SUSv3 устанавливает, что сигнал должен отправляться всем процессам группы за исключением «неуказанного набора системных процессов»; это же замечание касается всех остальных случаев.)
• Если pid меньше –1, то сигнал отправляется во все процессы группы, идентификатор которой равняется абсолютному значению аргумента pid. Такая отправка сигнала находит свое применение в управлении заданиями оболочки (см. раздел 34.7).
• Если pid равен –1, сигнал отправляется во все процессы, в которые у вызывавшего процесса есть разрешение отправлять сигналы, за исключением init (ID процесса равен 1) и вызывающего процесса. Если сигнал подается привилегированным процессом, он будет доставлен во все процессы в системе, кроме двух выше обозначенных. Сигналы, отправляемые таким образом, называются
Если ни один из процессов не подходит под указанный в аргументе pid идентификатор, то функция kill() завершается с ошибкой и устанавливает для переменной errno значение ESRCH («Нет такого процесса»). Процессу для отправки сигнала другому требуются соответствующие разрешения. Далее перечислены правила доступа:
• Привилегированный (CAP_KILL) процесс может посылать сигналы в любой процесс.
• Процесс init (ID процесса 1), запущенный пользователем и группой root, — особый случай. В него можно посылать только те сигналы, для которых у него установлены обработчики. Это предотвращает возникновение ситуаций, когда системный администратор случайно аварийно завершает процесс init, фундаментальный для работы системы.