sent signal 43, val = 0
sent signal 43, val = 1
sent signal 43, val = 2
solaris % родительский процесс завершил работу, пауза 3 секунды,
пока дочерний процесс не разблокирует сигналы
received signal #45, code = –2, ival = 2 дочерний процесс получает сигналы
received signal #45, code = –2, ival = 1
received signal #45, code = –2, ival = 0
received signal #44, code = –2, ival = 2
received signal #44, code = –2, ival = 1
received signal #44, code = –2, ival = 0
received signal #43, code = –2, ival = 2
received signal #43, code = –2, ival = 1
received signal #43, code = –2, ival = 0
В очередь помещаются девять сигналов, но первыми принимаются сигналы с большими номерами (а мы ожидали получить сигналы с меньшими номерами).
Кроме того, сигналы с одинаковым номером приходят в порядке LIFO, а не FIFO. Код si_code = –2 соответствует SI_QUEUE.
Запустив программу в Digital Unix 4.0B, мы получим именно тот результат, которого ожидали:
alpha % test1
SIGRTMIN = 33, SIGRTMAX = 48 16 сигналов реального времени
трех секундная пауза
sent signal 48, val = 0
sent signal 48, val = 1
sent signal 48, val = 2
sent signal 47, val = 0
sent signal 47, val = 1
sent signal 47, val = 2
sent signal 46, val = 0
sent signal 46, val = 1
sent signal 46, val = 2
alpha % родительский процесс завершил работу, пауза 3 секунды.
пока дочерний процесс не разблокируетсигналы
received signal #46, code – –1, ival = 0 дочерний процесс получает сигналы
received signal #46, code = –1, ival = 1
received signal #46, code = –1, ival = 2
received signal #47, code – –1, ival = 0
received signal #47, code = –1, ival = 1
received signal #47, code = –1, ival = 2
received signal #48, code = –1, ival = 0
received signal #48, code = –1, ival = 1
received signal #48, code = –1, ival = 2
Девять сигналов помещаются в очередь и получаются адресатом в ожидаемом порядке: первым приходит сигнал с меньшим номером, а копии сигнала приходят в порядке FIFO.
ПРИМЕЧАНИЕ
Похоже, что в реализации Solaris 2.6 есть ошибка.
Функция signal_rt
В книге [24, с. 120] мы привели пример собственной функции signal, вызывавшей функцию sigaction стандарта Posix для установки обработчика сигнала, обеспечивающего надежную семантику Posix. Изменим эту функцию, чтобы обеспечить поддержку реального времени. Новую функцию мы назовем signal_rt; ее текст приведен в листинге 5.15.
//lib/signal_rt.c
1 #include "unpipc.h"
2 Sigfunc_rt *
3 signal_rt(int signo, Sigfunc_rt *func)
4 {
5 struct sigaction act, oact;
6 act.sa_sigaction = func; /* сохраняем адрес функции */
7 sigemptyset(&act.sa_mask);
8 act.sa_flags = SA_SIGINFO; /* гарантирует режим реального времени */
9 if (signo == SIGALRM) {
10 #ifdef SA_INTERRUPT
11 act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
12 #endif
13 } else {
14 #ifdef SA_RESTART
15 act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
16 #endif
17 }
18 if (sigaction(signo, &act, &oact) < 0)
19 return((Sigfunc_rt *) SIG_ERR);
20 return(oact.sa_sigaction);
21 }
1-3 В нашем заголовочном файле unpiрс.h (листинг В.1) мы определяем Sigfunc_rt как
typedef void Sigfunc_rt(int, siginfo_t*, void*);
Ранее в этом разделе мы говорили о том, что это прототип функции для обработчика сигнала, устанавливаемого с флагом SA_SIGINFO.
Структура sigaction претерпела изменения с добавлением поддержки сигна-5-7 лов реального времени: к ней было добавлено новое поле sa_sigaction:
struct sigaction {
void (*sa_handler)(); /* SIG_DFL, SIG_IGN или адрес обработчика сигнала */
sigset_t sa_mask; /* дополнительные блокируемые сигналы */
int sa_flags; /* параметры сигналов: SA_XXX */
void (*sa_sigaction)(int, siginfo_t, void *);
};
Правила действуют следующие:
■ Если в поле sa_flags установлен флаг SA_SIGINFO, поле sa_sigaction указывает адрес функции-обработчика сигнала.
■ Если флаг SA_SIGINFO не установлен, поле sa_handler указывает адрес функции-обработчика сигнала.
■ Чтобы сопоставить сигналу действие по умолчанию или игнорировать его, следует установить sa_handler равным либо SIG_DFL, либо SIG_IGN и не устанавливать флаг SA_SIGINFO.
8-17 Мы всегда устанавливаем флаг SA_SIGINFO и указываем флаг SA_RESTART, если перехвачен какой-либо другой сигнал, кроме SIGALRM.
5.8. Реализация с использованием отображения в память
Теперь рассмотрим реализацию очередей сообщений Posix с использованием отображения в память, взаимных исключений и условных переменных Posix.
ПРИМЕЧАНИЕ
Взаимные исключения и условные переменные описаны в главе 7, а ввод-вывод с отображением в память — в главах 12 и 13. Вы можете отложить данный раздел до ознакомления с этими главами.
На рис. 5.2 приведена схема структур данных, которыми мы пользуемся для реализации очереди сообщений Posix. Изображенная очередь может содержать до четырех сообщений по 7 байт каждое.
В листинге 5.16 приведен заголовочный файл mqueue.h, определяющий основные структуры, используемые в этой реализации.
Дескриптор нашей очереди сообщений является просто указателем на структуру mq_infо. Каждый вызов mq_open выделяет память под одну такую структуру, а вызвавшему возвращается указатель на нее. Повторим, что дескриптор очереди сообщений не обязательно является небольшим целым числом, как дескриптор файла — единственное ограничение, накладываемое Posix, заключается в том, что этот тип данных не может быть массивом.
//my_pxmsg_mmap/mqueue.h
1 typedef struct mymq_info *mymqd_t;