continue; /* Запуск в течение нескольких секунд */

printPendingSigs(stdout,

"Before sigsuspend() — pending signals: \n");

if (sigsuspend(&origMask) == –1 && errno!= EINTR)

errExit("sigsuspend");

}

if (sigprocmask(SIG_SETMASK, &origMask, NULL) == –1)

errExit("sigprocmask — SIG_SETMASK");

printSigMask(stdout, "=== Exited loop\nRestored signal mask to: \n");

/* Выполнение других команд… */

exit(EXIT_SUCCESS);

}

signals/t_sigsuspend.c

Следующий журнал сессии оболочки показывает пример того, что мы можем увидеть на экране при запуске программы из листинга 22.5:

$ ./t_sigsuspend

Initial signal mask is:

=== LOOP 1

Starting critical section, signal mask is:

2 (Interrupt)

3 (Quit)

Нажмите Ctrl+C; SIGINT сгенерирован, но остается в режиме ожидания, так как заблокирован

Before sigsuspend() — pending signals:

2 (Interrupt)

Caught signal 2 (Interrupt) Вызов sigsuspend(), сигналы разблокированы

Последняя строка вывода появилась на экране, когда программа вызвала функцию sigsuspend(), разблокировавшую сигнал SIGINT. В этот момент был вызван обработчик, отобразивший эту строку.

Основная программа продолжает цикл:

=== LOOP 2

Starting critical section, signal mask is:

2 (Interrupt)

3 (Quit)

Нажмите Ctrl+\ для генерации SIGQUIT

Before sigsuspend() — pending signals:

3 (Quit)

Caught signal 3 (Quit) Вызов sigsuspend(), сигналы разблокированы

=== Exited loop Обработчик сигнала установил gotSigquit

Restored signal mask to:

В этот раз мы нажали сочетание выхода Ctrl+\, заставившее обработчик сигнала установить флаг gotSigquit, который, в свою очередь, заставил программу завершить цикл.

22.10. Синхронное ожидание сигнала

В разделе 22.9 мы увидели, как использовать обработчик сигнала вместе с функцией sigsuspend() для приостановки выполнения процесса до того, как будет доставлен сигнал. Однако необходимость написания обработчика сигнала и обработки сложностей асинхронной доставки делает некоторые приложения громоздкими. Вместо этого мы можем использовать системный вызов sigwaitinfo() для реализации синхронного приема сигнала.

Функция sigwaitinfo() приостанавливает выполнение процесса до тех пор, пока из набора, указываемого аргументом set, не будет ожидать по крайней мере один сигнал. Если в наборе set один сигнал уже находится в режиме ожидания во время вызова, тогда функция sigwaitinfo() выполняет возврат незамедлительно. Этот сигнал удаляется из списка ожидания, а его номер возвращается как результат выполнения функции. Если значение info не равно NULL, то данный аргумент указывает на структуру siginfo_t, инициализацируемую для хранения той же самой информации, что и предоставляется обработчику сигнала через аргумент siginfo_t (см. раздел 21.4).

#define _POSIX_C_SOURCE 199309

#include

int sigwaitinfo(const sigset_t *set, siginfo_t *info);

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

Очередность доставки и характеристики очереди сигналов, принимаемых функцией sigwaitinfo(), аналогичны свойствам сигналов, перехватываемых обработчиками. Иными словами, стандартные сигналы не ставятся в очередь, тогда как сигналы реального времени ставятся в очередь и доставляются по возрастанию номера сигнала.

Ожидание сигналов с использованием функции sigwaitinfo() не только избавляет от лишнего кода при написании обработчиков сигналов, но и является несколько более быстрым решением по сравнению с сочетанием «обработчик сигнала + функция sigsuspend()» (см. упражнение 22.3).

Обычно имеет смысл использовать функцию sigwaitinfo() только в сочетании с блокированием сигналов, в ожидании которых мы заинтересованы. (Мы можем получить ожидающий сигнал с помощью функции sigwaitinfo() даже в то время, когда он заблокирован). Если мы не сможем этого сделать и сигнал будет доставлен в процесс перед первым или между двумя успешными вызовами функции sigwaitinfo(), то такой сигнал будет обработан в соответствии с его текущей диспозицией.

Согласно стандарту SUSv3 вызов sigwaitinfo() без блокировки сигналов, указанных в аргументе set, приводит к неопределенному поведению. Пример использования функции sigwaitinfo() приведен в листинге 22.6. Эта программа сначала блокирует все сигналы, а затем делает отсрочку на количество секунд, указанное в необязательном аргументе командной строки. Это позволяет отправлять сигналы в программу перед вызовом sigwaitinfo(). Затем программа выполняет цикл с sigwaitinfo() до тех пор, пока не получит сигнал SIGINT или SIGTERM.

Следующий журнал сессии оболочки демонстрирует выполнение программы из листинга 22.6. Мы запускаем программу в фоновом режиме, указываем, что она должна сделать отсрочку на 60 секунд перед вызовом sigwaitinfo(), а затем отправляем в нее два сигнала:

$ ./t_sigwaitinfo 60 &

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

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