•
SA_NOCLDSTOP
— используется только для сигнала
SIGCHLD
; флаг указывает системе не генерировать для родительского процесса
SIGCHLD
от порожденных процессов, которые завершаются посредством
SIGSTOP
.
•
SA_SIGINFO
— при этом будет использована обработка сигналов на базе очереди сигналов (модель сигналов реального времени). По умолчанию используется простая обработка: результат воздействия нескольких сигналов определяется последним поступившим. В случае установки этого флага будет использована расширенная форма обработчика
sa_sigaction
(при этом поле
sa_handler
не будет использоваться)
[30]. Обработчику будет передаваться дополнительная информация о сигнале — структура
siginfo_t
(его номер, PID пославшего сигнал процесса, действующий идентификатор пользователя этого процесса). Эта весьма объемная структура будет очень кратко рассмотрена ниже.
[31]Ее описание вынесено в отдельный заголовочный файл
и может быть изучено там.
Приведем несколько небольших и самых простых примеров использования модели надежных сигналов.
1. Перехватчик сигнала
SIGINT
(реакция на пользовательский ввод [Ctrl+C])
[32](
void catchint(int signo) {
cout << "SIGINT: signo = " << signo << endl;
}
int main {
static struct sigaction act = { &catchint, 0, (sigset_t)0 };
// запрещаем любые сигналы на время обработки SIGINT:
sigfillset(&(act.sa_mask));
// до этого вызова реакцией на Ctrl+C будет завершение задачи:
sigaction(SIGINT, &act, NULL);
for (int i = 0; i < 20; i++)
sleep(1), cout << "Cycle # " << i << endl;
}
Результатом нормального (без вмешательства оператора) выполнения приложения будет последовательность из 20 циклов секундных ожиданий, но если в процессе этих ожиданий пользователь пытается прервать работу процесса по [Ctrl+C], то он получит вывод, подобный следующему:
...
Cycle # 10
... здесь пользователь пытается прервать программу
SIGINT: signo = 2
Cycle # 11
...
2. Запрет прерывания выполнения программы с терминала. Для этого достаточно заменить строку инициализации структуры
sigaction
на:
static struct sigaction act = { SIG_IGN, 0, (sigset_t)0 };
Можно проигнорировать сразу несколько сигналов (прерывающих выполнение программы с клавиатуры):
sigaction(SIGINT, &act, NULL );
sigaction(SIGQUIT, &act, NULL);
Далее остановимся еще на одном вызове API-сигналов, который широко используется в этой и последующих моделях обработки (сигналы реального времени, реакция в потоках):
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
Этот вызов позволяет прочитать текущее значение (если
set
установлено в
NULL
, то параметр
how
игнорируется) или переустановить сигнальную маску для текущего потока. Параметры вызова:
•
set
— это то значение, в соответствии с которым корректируется сигнальная маска процесса;
•
how
— указывает, какое именно действие переустановки сигнальной маски требуется осуществить:
•
SIG_BLOCK
— добавить сигналы, указанные в set к маске процесса (заблокировать реакцию на эти сигналы);
•
SIG_UNBLOCK
— сбросить указанные set сигналы в сигнальной маске;
•
SIG_SETMASK
— переустановить сигнальную маску процесса на значение, указанное в
set
.
•
oset
— значение, в котором будет сохранено значение маски, предшествующее вызову (старое значение).
Как и большинство сигнальных функций, данная функция возвращает нулевое значение в результате успешного выполнения и -1 в случае неудачи, при этом код ошибки устанавливается в
errno
.
Именно эта функция снимает одно из самых существенных ограничений, свойственных модели «ненадежных сигналов», — позволяет заблокировать реакцию на сигналы при выполнении критических участков кода и восстановить ее при завершении выполнения этих участков.
Модель сигналов реального времени
Сигналы реального времени были добавлены в POSIX относительно недавно (1996 г.). Эта новая модель в различных ОС UNIX реализуется с разной степенью полноты и с отклонениями от спецификаций, и QNX не исключение. Модель еще до конца не отработана, поэтому возможны сюрпризы (и сейчас они будут).