Поля структуры timespec заполняются для указания максимального количества секунд и наносекунд, на протяжение которых функция sigtimedwait() будет ожидать сигнал. Присвоение обоим полям структуры значения 0 приводит к незамедлительному тайм-ауту, иными словами — к опросу на предмет того, что хотя бы один из указанных сигналов находится в режиме ожидания. Если вызов завершается с тайм-аутом, при этом ни один сигнал так и не был доставлен, то функция sigtimedwait() возвращает ошибку EAGAIN.
Если аргумент timeout равен NULL, функция sigtimedwait() является абсолютным эквивалентом sigwaitinfo(). В SUSv3 значение NULL аргумента timeout не прописано, и в некоторых реализациях UNIX данное значение интерпретируется как запрос на проведение опроса, незамедлительно возвращающего результат.
Начиная с версии ядра 2.6.22, в Linux предоставляется (нестандартный) системный вызов signalfd(), создающий специальный файловый дескриптор, из которого можно прочитать сигналы, направляемые в вызывающий участок кода. Механизм signalfd предоставляет альтернативу функции sigwaitinfo() для синхронного приема сигналов.
#include
int signalfd(int
Возвращает файловый дескриптор при успешном завершении или –1 при ошибке
Аргумент mask — это набор сигналов, в котором перечислены те сигналы, которые мы хотим иметь возможность прочитать через файловый дескриптор signalfd. Как и в случае с функцией sigwaitinfo(), как правило, нам следует также заблокировать все сигналы, перечисленные в mask, с помощью функции sigprocmask(), чтобы они не обрабатывались в соответствии с их диспозициями по умолчанию прежде, чем мы сможем их прочитать.
Если аргумент fd указан как –1, то функция signalfd() создает новый файловый дескриптор, который может использоваться для чтения сигналов в mask. В противном случае она изменяет маску, связанную с fd, значением которого должен быть файловый дескриптор, созданный предшествующим вызовом signalfd().
В изначальной реализации аргумент flags был зарезервирован для будущего и его необходимо было указывать как 0. Однако, начиная с версии Linux 2.6.27, функция стала поддерживать два флага:
• SFD_CLOEXEC — установить флаг «закрыть при выходе» (FD_CLOEXEC) для нового файлового дескриптора. Этот флаг полезен по тем же причинам, что и флаг O_CLOEXEC вызова open(), описанный в разделе 4.3.1;
• SFD_NONBLOCK — установить флаг O_NONBLOCK для соответствующего файлового дескриптора. Таким образом, дальнейшие чтения будут неблокирующими.
Создав файловый дескриптор, мы можем затем считывать из него сигналы с помощью функции read(). Буфер, переданный функции read(), должен быть достаточно большим для хранения хотя бы одной структуры signalfd_siginfo, определенной следующим образом в файле
struct signalfd_siginfo {
uint32_t ssi_signo; /* Номер сигнала */
int32_t ssi_errno; /* Номер ошибки (обычно не используется) */
int32_t ssi_code; /* Код сигнала */
uint32_t ssi_pid; /* ID процесса-отправителя */
uint32_t ssi_uid; /* Реальный ID пользователя процесса-отправителя */
int32_t ssi_fd; /* Файловый дескриптор (SIGPOLL/SIGIO) */
uint32_t ssi_tid; /* ID внутреннего таймера ядра (таймеры POSIX) */
uint32_t ssi_band; /* Связывающее событие (SIGPOLL/SIGIO) */
uint32_t ssi_overrun; /* Счетчик превышений таймера (таймеры POSIX)*/
uint32_t ssi_trapno; /* Номер ловушки */
int32_t ssi_status; /* Код завершения или сигнал (SIGCHILD) */
int32_t ssi_int; /* Целое число, отправленное функцией sigqueue() */
uint64_t ssi_ptr; /* Указатель, отправленный функцией sigqueue() */
uint64_t ssi_utime; /* Пользовательское время ЦП (SIGCHLD) */
uint64_t ssi_stime; /* Системное время ЦП (SIGCHLD) */
uint64_t ssi_addr; /* Адрес, сгенерировавший сигнал
(только аппаратно генерируемые сигналы) */
};
Поля этой структуры возвращают ту же информацию, что и поля традиционной структуры siginfo_t с похожими именами (см. раздел 21.4).
Каждый вызов функции read() возвращает столько экземпляров структуры signalfd_siginfo, сколько ожидающих сигналов поместится в предоставленный буфер. Если во время вызова функции нет ожидающих сигналов, функция read() блокируется до поступления сигнала. Мы также можем воспользоваться операцией fcntl() F_SETFL (см. раздел 5.3), чтобы установить флаг O_NONBLOCK для файлового дескриптора. Таким образом, операции чтения будут неблокирующими и будут возвращать ошибку EAGAIN при отсутствии сигналов в режиме ожидания.
При чтении сигнала из файлового дескриптора signalfld, он считается потребленным и выходит из режима ожидания процесса.
Листинг 22.7. Использование signalfld() для чтения сигналов
signals/singalfd_sigval.c
#include
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
sigset_t mask;
int sfd, j;
struct signalfd_siginfo fdsi;
ssize_t s;
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s sig-num…\n", argv[0]);