Поля структуры timespec заполняются для указания максимального количества секунд и наносекунд, на протяжение которых функция sigtimedwait() будет ожидать сигнал. Присвоение обоим полям структуры значения 0 приводит к незамедлительному тайм-ауту, иными словами — к опросу на предмет того, что хотя бы один из указанных сигналов находится в режиме ожидания. Если вызов завершается с тайм-аутом, при этом ни один сигнал так и не был доставлен, то функция sigtimedwait() возвращает ошибку EAGAIN.

Если аргумент timeout равен NULL, функция sigtimedwait() является абсолютным эквивалентом sigwaitinfo(). В SUSv3 значение NULL аргумента timeout не прописано, и в некоторых реализациях UNIX данное значение интерпретируется как запрос на проведение опроса, незамедлительно возвращающего результат.

22.11. Получение сигналов через файловый дескриптор

Начиная с версии ядра 2.6.22, в Linux предоставляется (нестандартный) системный вызов signalfd(), создающий специальный файловый дескриптор, из которого можно прочитать сигналы, направляемые в вызывающий участок кода. Механизм signalfd предоставляет альтернативу функции sigwaitinfo() для синхронного приема сигналов.

#include

int signalfd(int fd, const sigset_t *mask, int flags);

Возвращает файловый дескриптор при успешном завершении или –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]);

Перейти на страницу:

Похожие книги