Для временного предотвращения доставки сигнала можно использовать последовательность вызовов, приведенных в листинге 20.5, для блокировки и последующей разблокировки сигнала путем сброса сигнальной маски к ее предыдущему состоянию.
Листинг 20.5. Временное блокирование доставки сигнала
sigset_t blockSet, prevMask;
/* Инициализировать набор сигналов сигналом SIGINT */
sigemptyset(&blockSet);
sigaddset(&blockSet, SIGINT);
/* Блокировать SIGINT, сохранить предыдущую сигнальную маску */
if (sigprocmask(SIG_BLOCK, &blockSet, &prevMask) == –1)
errExit("sigprocmask1");
/*… Код, который нельзя прервать сигналом SIGINT… */
/* Восстановить предыдущую сигнальную маску, разблокировать SIGINT */
if (sigprocmask(SIG_SETMASK, &prevMask, NULL) == –1)
errExit("sigprocmask2");
Стандарт SUSv3 устанавливает, что если один из ожидающих сигналов разблокирован вызовом функции sigprocmask(), то хотя бы один из этих сигналов будет доставлен до того, как вызов будет возвращен. Иными словами, если мы разблокируем ожидающий сигнал, то он будет незамедлительно доставлен в процесс.
Попытки заблокировать сигналы SIGKILL и SIGSTOP игнорируются без оповещения. Если мы попытаемся заблокировать эти сигналы, функция sigprocmask() не только не даст доступа к ним, но и не сгенерирует ошибку. Это значит, что мы можем использовать следующий код для блокировки всех сигналов, за исключением сигналов SIGKILL и SIGSTOP:
sigfillset(&blockSet);
if (sigprocmask(SIG_BLOCK, &blockSet, NULL) == –1)
errExit("sigprocmask");
Если процесс получает сигнал, который в данный момент подлежит блокированию, то он добавляется в набор ожидающих сигналов. Когда (и если) сигнал будет разблокирован в дальнейшем, он будет доставлен в процесс. Для определения того, какие сигналы процесса находятся в режиме ожидания, мы можем вызвать функцию sigpending().
#include
int sigpending(sigset_t *
Возвращает 0 при успешном завершении или –1 при ошибке
Системный вызов sigpending() возвращает набор сигналов, находящихся в режиме ожидания процесса в структуре sigset_t, на которую указывает аргумент set. После этого мы сможем проверить содержимое структуры set с помощью функции sigismember(), описанной в разделе 20.9.
Если диспозиция ожидающего сигнала изменяется, то при последующем разблокировании данный сигнал будет обработан в соответствии со вновь заданной диспозицией. Это может быть полезно для предотвращения доставки ожидающего сигнала путем изменения его диспозиции на SIG_IGN или SIG_DFL (если действие по умолчанию для данного сигнала —
Набор ожидающих сигналов — это лишь маска, она показывает факт возникновения того или иного сигнала, но не количество возникновений. Иными словами, если один и тот же сигнал был сгенерирован несколько раз, будучи заблокированным, то он записывается в набор ожидающих сигналов, а затем доставляется, но лишь однажды. (Одно из различий между стандартными сигналами и сигналами реального времени заключается в том, что вторые ставятся в очередь, как описано в разделе 22.8.)
В листингах 20.6 и 20.7 показаны две программы, которые применяются для наблюдения того, как сигналы могут быть не поставлены в очередь. Программа в листинге 20.6 принимает четыре аргумента командной строки, следующим образом:
$ ./sig_sender PID num-sigs sig-num [sig-num-2]
Первый аргумент — это идентификатор процесса, в который программа должна отправлять сигналы. Второй определяет количество сигналов, подлежащих отправке в целевой процесс. Третий аргумент устанавливает номер сигнала, подлежащего отправке в целевой процесс. Если в качестве четвертого аргумента предоставляется номер сигнала, то программа отправляет один экземпляр этого сигнала после отправки сигналов, указанных предыдущими аргументами. В примере сессии оболочки ниже мы используем последний аргумент для отправки сигнала SIGINT в целевой процесс. Назначение отправки данного сигнала вы поймете в ближайшее время.
Листинг 20.6. Отправка нескольких сигналов
signals/sig_sender.c
include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
int numSigs, sig, j;
pid_t pid;
if (argc < 4 || strcmp(argv[1], "-help") == 0)
usageErr("%s pid num-sigs sig-num [sig-num-2]\n", argv[0]);
pid = getLong(argv[1], 0, "PID");
numSigs = getInt(argv[2], GN_GT_0, "num-sigs");
sig = getInt(argv[3], 0, "sig-num");
/* Отправить сигналы получателю */
printf("%s: sending signal %d to process %ld %d times\n",
argv[0], sig, (long) pid, numSigs);
for (j = 0; j < numSigs; j++)
if (kill(pid, sig) == –1)
errExit("kill");
/* Если был указан четвертый аргумент командной строки, отправить этот сигнал */
if (argc > 4)
if (kill(pid, getInt(argv[4], 0, "sig-num-2")) == –1)
errExit("kill");