• Поле si_value содержит данные, указанные в аргументе value (объединение sigval) процессом, пославшим сигнал с помощью функции sigqueue().
• Поля si_pid и si_uid содержат соответственно идентификатор процесса и реальный идентификатор пользователя процесса, отправившего сигнал.
В листинге 22.3 приводится пример обработки сигналов реального времени. Программа перехватывает сигналы и выводит на экран значения различных полей структуры siginfo_t, передаваемой ей обработчиком сигнала. Программа принимает два необязательных целочисленных аргумента командной строки.
Если указан первый аргумент, то программа блокирует все сигналы и затем переходит в режим сна на количество секунд, указанное в этом аргументе. В это время мы можем поставить в очередь к процессу несколько сигналов реального времени и пронаблюдать, что произойдет, когда сигналы будут разблокированы. Второй аргумент задает количество секунд, на протяжении которых обработчик сигнала должен оставаться в режиме сна перед возвратом управления. Указание ненулевого значения (значение по умолчанию 1) может быть полезным для замедления работы программы с тем, чтобы мы могли более четко увидеть, что происходит, когда обрабатываются несколько сигналов.
Мы можем использовать программу из листинга 22.3 вместе с программой из листинга 22.2 (t_sigqueue.c) для изучения поведения сигналов реального времени, как показано в следующем журнале сессии оболочки:
$ ./catch_rtsigs 60 &
[1] 12842
$ ./catch_rtsigs: PID is 12842
./catch_rtsigs: signals blocked — sleeping 60 seconds
$ ./t_sigqueue 12842 54 100 3
./t_sigqueue: PID is 12843, UID is 1000
$ ./t_sigqueue 12842 43 200
./t_sigqueue: PID is 12844, UID is 1000
$ ./t_sigqueue 12842 40 300
./t_sigqueue: PID is 12845, UID is 1000
Со временем программа catch_rtsigs выходит из режима сна и начинает выводить на печать сообщения по мере того, как обработчик перехватывает различные сигналы. (На экране мы видим, что приглашение оболочки смешивается с программным выводом. Это происходит потому, что программа catch_rtsigs распечатывает информацию из фонового режима.) Мы видим, что сигналы реального времени с меньшим номером доставляются первыми, а также что структура siginfo_t, передаваемая обработчику, содержит PID и UID процесса, пославшего сигнал:
$ ./catch_rtsigs: sleep complete
caught signal 40
si_signo=40, si_code=–1 (SI_QUEUE), si_value=300
si_pid=12845, si_uid=1000
caught signal 43
si_signo=43, si_code=–1 (SI_QUEUE), si_value=200
si_pid=12844, si_uid=1000
Оставшийся вывод производится тремя экземплярами одного и того же сигнала реального времени. Просмотрев значения поля si_value, мы можем увидеть, что эти сигналы были доставлены в том же порядке, в котором они были отправлены:
caught signal 54
si_signo=54, si_code=–1 (SI_QUEUE), si_value=100
si_pid=12843, si_uid=1000
caught signal 54
si_signo=54, si_code=–1 (SI_QUEUE), si_value=101
si_pid=12843, si_uid=1000
caught signal 54
si_signo=54, si_code=–1 (SI_QUEUE), si_value=102
si_pid=12843, si_uid=1000
Далее мы воспользуемся командой оболочки kill для отправки сигнала в программу catch_rtsigs. Как и раньше, мы увидим, что структура siginfo_t, получаемая обработчиком, включает идентификатор процесса и идентификатор (имя) пользователя процесса, пославшего сигнал, однако в этом случае значение поля si_code — константа SI_USER:
$ echo $$
12780
$ kill -40 12842
$ caught signal 40
si_signo=40, si_code=0 (SI_USER), si_value=0
si_pid=12780, si_uid=1000
$ kill 12842
Caught 6 signals
[1]+ Done./catch_rtsigs 60
Листинг 22.3. Обработка сигналов реального времени
signals/catch_rtsigs.c
#define _GNU_SOURCE
#include
#include
#include "tlpi_hdr.h"
static volatile int handlerSleepTime;
static volatile int sigCnt = 0; /* Количество полученных сигналов */
static volatile int allDone = 0;
static void /* Обработчик для сигналов, установленных с SA_SIGINFO */