Аргумент 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
{
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);
errExit("sigaction");
/* Создаем и запускаем по одному таймеру для каждого аргумента командной строки */
sev.sigev_notify = SIGEV_SIGNAL; /* Уведомляем с помощью сигнала */
sev.sigev_signo = TIMER_SIG; /* Указываем сигнал для уведомления */
for (j = 0; j < argc — 1; j++) {
sev.sigev_value.sival_ptr = &tidlist[j];
/* Позволяем обработчику получить идентификатор этого таймера */
errExit("timer_create");
printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);
errExit("timer_settime");
}
pause();
}
timers/ptmr_sigev_signal.c
Каждый из аргументов командной строки в программе из листинга 23.5 представляет собой начальное значение и интервал таймера. Их синтаксис описан в сообщении usageErr, которое выводится в сессии командной строки чуть ниже. Программа выполняет такие шаги.
• Устанавливает обработчик для сигнала, который используется таймером для уведомления
• Создает