union sigval si_value; /* целое или указатель от отправителя */
} siginfo_t;
В QNX
sigval
определяется так (подобное определение дают и другие ОС UNIX):
union sigval {
int sival_int;
void *sival_ptr;
};
Это 32-битное значение предназначено для посылки совместно с сигналом данных для получателя, которые, как видно из синтаксиса определения
sigval
, могут быть целочисленным значением или указателем неспецифицированного типа.
7. Поле
si_code
типа
siginfo_t
, передаваемое получателю, определяет природу возбуждения сигнала:
•
SI_ASINCIO
— сигнал порожден завершением операций асинхронного ввода/вывода, запущенного одной из функций POSIX
aio_*()
;
•
SI_MESGQ
— сигнал возбуждается при помещении сообщения в пустую очередь сообщений UNIX;
•
SI_QUEUE
— сигнал был отправлен функцией
sigqueue()
(в этом разделе нас интересуют только такие сигналы);
•
SI_TIMER
— сигнал был порожден по истечении установленного времени интервального таймера;
•
SI_USER
— сигнал был отправлен функцией
kill()
.
8. Допускается, что при возбуждении сигнала еще каким-либо механизмом (сверх перечисленных, что может определяться специфическими особенностями ОС) значение
si_code
может отличаться от перечисленных. Однако значение поля
si_value
считается актуальным только в тех случаях, когда
si_code
имеет одно из значений:
SI_ASINCIO
,
SI_MESGQ
,
SI_QUEUE
,
SI_TIMER
.
9. Согласно POSIX сигналы, обработчики для которых также устанавливаются с флагом
SA_SIGINFO
, но не входящие в диапазон сигналов реального времени, например стандартные сигналы UNIX, могут обрабатываться как на основе помещения их в очередь, так и без ее использования; выбор оставляется на усмотрение разработчика ОС.
Мы перечислили основные требования POSIX к модели обработки сигналов реального времени. Дополнения, отличия и специфические структуры данных QNX будут рассмотрены немного позже.
Весьма доходчивый пример для проверки и иллюстрации обработки сигналов реального времени приведен У. Стивенсом [2]. Мы же построим приложение, реализующее его основную идею: [33]
#include
#include
#include
#include
#include
static void handler(int signo, siginfo_t* info, void* context) {
cout << "received signal " << signo << " code = " << info->si_code <<
" val = " << info->si_value.sival_int << endl;
}
int main(int argc, char *argv[]) {
cout << "signal SIGRTMIN=" << (int)SIGRTMIN
<< " - signal SIGRTMAX=" << (int)SIGRTMAX << endl;
int opt, val, beg = SIGRTMAX, num = 3,
fin = SIGRTMAX - num, seq = 3;
// обработка параметров запуска:
while ((opt = getopt(argc, argv, "b:e n")) != -1) {
switch(opt) {
case 'b': // начальный сигнал серии
if (sscanf(optarg, "%i", &val) != 1)
perror("parse command line failed"), exit(EXIT_FAILURE);
beg = val;
break;
case 'e': // конечный сигнал серии
if (sscanf(optarg, "%i", &val) != 1)
perror("parse command line failed"), exit(EXIT_FAILURE);
fin = val;
break;
case 'n': // количество сигналов в группе посылки
if (sscanf(optarg, "%i", &val) != 1)
perror("parse command line failed"), exit(EXIT_FAILURE);
seq = val;
break;
default:
exit(EXIT_FAILURE);
}
}
num = fin - beg;
fin += num > 0 ? 1 : -1;
sigset_t sigset;
sigemptyset(&sigset);
for (int i = beg; i != fin; i += (num > 0 ? 1 : -1))
sigaddset(&sigset, i);
pid_t pid;
// вот здесь ветвление на 2 процесса
if (pid - fork() == 0) {
// дочерний процесс, здесь будут приниматься посланные сигналы
sigprocmask(SIG_BLOCK, &sigset, NULL);
for (int i = beg; i != fin; i += (num > 0 ? 1 : -1)) {