Аргумент timerid представляет собой идентификатор, возвращенный предыдущим вызовом timer_create(). Если таймер был запущен, перед удалением он автоматически останавливается. Сигнал о срабатывании данного таймера, который уже успел попасть в очередь, сохраняется (этот момент не описан в стандарте SUSv3, поэтому другие системы могут вести себя иначе). Таймеры автоматически удаляются при завершении процесса.

23.6.5. Уведомление с помощью сигнала

Если мы выбрали сигналы в качестве способа доставки уведомлений, для их получения можно применить либо обработчик, либо вызов sigwaitinfo() или sigtimedwait(). Оба варианта позволяют принимающему процессу получить структуру siginfo_t (см. раздел 21.4) с подробностями о сигнале (чтобы воспользоваться этой возможностью в обработчике сигнала, во время его установки нужно указать флаг SA_SIGINFO). В структуре siginfo_t заполнены следующие поля.

• si_signo — содержит сигнал, сгенерированный таймером.

• si_code — хранит значение SI_TIMER; это означает, что сигнал был сгенерирован при срабатывании POSIX-таймера.

• si_value — содержит значение, которое было указано в поле evp.sigev_value при создании таймера с помощью вызова timer_create(). Использование разных значений в evp.sigev_value позволяет различать срабатывания разных таймеров, которые доставляют один и тот же сигнал.

При создании таймера полю evp.sigev_value.sival_ptr обычно назначается адрес аргумента timerid, который передается в том же вызове timer_create() (листинг 23.5). Это позволяет обработчику сигнала (или вызову sigwaitinfo()) получить идентификатор таймера, который сгенерировал сигнал (как вариант, полю evp.sigev_value.sival_ptr можно было бы назначить адрес структуры, которая содержит тот же аргумент timerid).

В Linux структура siginfo_t также поддерживает нестандартное поле si_overrun. Оно содержит счетчик дополнительных срабатываний данного таймера (описывается в подразделе 23.6.6).

Linux предоставляет еще одно нестандартное поле: si_timerid. Оно хранит идентификатор, который используется системой для определения таймера (он не совпадает с идентификатором, который возвращает вызов timer_create()). Для прикладных программ он бесполезен.

Использование сигналов в качестве механизма уведомления для POSIX-таймера демонстрируется в листинге 23.5.

Листинг 23.5. Уведомление о срабатывании POSIX-таймера с помощью сигнала

timers/ptmr_sigev_signal.c

#define _POSIX_C_SOURCE 199309

#include

#include

#include "curr_time.h" /* Объявляет currTime() */

#include "itimerspec_from_str.h" /* Объявляет itimerspecFromStr() */

#include "tlpi_hdr.h"

#define TIMER_SIG SIGRTMAX /* Наш сигнал для уведомления о срабатывании таймера */

static void

handler(int sig, siginfo_t *si, void *uc)

{

timer_t *tidptr;

tidptr = si->si_value.sival_ptr;

/* НЕБЕЗОПАСНО: этот обработчик вызывает функцию, не рассчитанную

на работу с асинхронными сигналами (printf(); см. подраздел 21.1.2) */

printf("[%s] Got signal %d\n", currTime("%T"), sig);

printf(" *sival_ptr = %ld\n", (long) *tidptr);

printf(" timer_getoverrun() = %d\n", timer_getoverrun(*tidptr));

}

int

main(int argc, char *argv[])

{

struct itimerspec ts;

struct sigaction sa;

struct sigevent sev;

timer_t *tidlist;

int j;

if (argc < 2)

usageErr("%s secs[/nsecs][: int-secs[/int-nsecs]]…\n", argv[0]);

tidlist = calloc(argc — 1, sizeof(timer_t));

if (tidlist == NULL)

errExit("malloc");

/* Устанавливаем обработчик для сигнала-уведомления */

sa.sa_flags = SA_SIGINFO;

sa.sa_sigaction = handler;

sigemptyset(&sa.sa_mask);

if (sigaction(TIMER_SIG, &sa, NULL) == –1)

errExit("sigaction");

/* Создаем и запускаем по одному таймеру для каждого аргумента командной строки */

sev.sigev_notify = SIGEV_SIGNAL; /* Уведомляем с помощью сигнала */

sev.sigev_signo = TIMER_SIG; /* Указываем сигнал для уведомления */

for (j = 0; j < argc — 1; j++) {

 itimerspecFromStr(argv[j + 1], &ts);

sev.sigev_value.sival_ptr = &tidlist[j];

/* Позволяем обработчику получить идентификатор этого таймера */

 if (timer_create(CLOCK_REALTIME, &sev, &tidlist[j]) == –1)

errExit("timer_create");

printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);

 if (timer_settime(tidlist[j], 0, &ts, NULL) == –1)

errExit("timer_settime");

}

for (;;) /* Ожидаем входящих сигналов, посланных таймером */

pause();

}

timers/ptmr_sigev_signal.c

Каждый из аргументов командной строки в программе из листинга 23.5 представляет собой начальное значение и интервал таймера. Их синтаксис описан в сообщении usageErr, которое выводится в сессии командной строки чуть ниже. Программа выполняет такие шаги.

• Устанавливает обработчик для сигнала, который используется таймером для уведомления .

• Создает и запускает для каждого аргумента командной строки POSIX-таймер с механизмом уведомления SIGEV_SIGNAL. Функция itimerspecFromStr(), с помощью которой мы конвертируем аргументы командной строки в структуры типа itimerspec, показана в листинге 23.6.

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

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