ИМЯ
timer_create - создаёт таймер POSIX для определённого процессаLIBRARY
Real-time library ( librt, -lrt)СИНТАКСИС
#include <signal.h> /* определения констант SIGEV_* */ #include <time.h>
int timer_create(clockid_t clockid, struct sigevent *_Nullable restrict sevp, timer_t *restrict timerid);
Требования
макроса
тестирования
свойств
для glibc (см.
feature_test_macros(7)):
timer_create():
_POSIX_C_SOURCE >= 199309L
ОПИСАНИЕ
Вызов timer_create() создаёт новый таймер для процесса. Идентификатор нового таймера возвращается в буфере, указанном в timerid, его значение не должно быть равно null. Данный идентификатор уникален для процесса, пока таймер не будет удалён. Новый таймер создаётся неактивным. В аргументе clockid задаются часы, которые используются в новом таймере для учёта времени. Это может быть одно из следующих значений:- CLOCK_REALTIME
- Настраиваемые системные часы реального времени.
- CLOCK_MONOTONIC
- Ненастраиваемые, постоянно идущие вперёд часы, отсчитывающие время с некоторой неопределённой точки в прошлом, которая не изменяется с момент запуска системы.
- CLOCK_PROCESS_CPUTIME_ID (начиная с Linux 2.6.12)
- Часы, измеряющие время ЦП (пользовательское и системное), затраченное вызывающим процессом (всеми его нитями).
- CLOCK_THREAD_CPUTIME_ID (начиная с Linux 2.6.12)
- Часы, измеряющие время ЦП (пользовательское и системное), затраченное вызывающей нитью.
- CLOCK_BOOTTIME (начиная с Linux 2.6.39)
- Подобно CLOCK_MONOTONIC, представляет монотонно растущие часы. Однако, если часы CLOCK_MONOTONIC не отсчитывают время когда система находится в состоянии ожидания (suspended), а часы CLOCK_BOOTTIME учитывают время в таком состоянии системы. Это полезно приложениям, которым необходимо учитывать состояние ожидания. CLOCK_REALTIME не подходят для таких приложений, так как эти часы подвержены скачкообразным изменениям системных часов.
- CLOCK_REALTIME_ALARM (начиная с Linux 3.0)
- Эти часы подобны CLOCK_REALTIME, но разбудят систему, если она находится с состоянии ожидания. Для установки таймера по этим часам вызывающий должен иметь мандат CAP_WAKE_ALARM.
- CLOCK_BOOTTIME_ALARM (начиная с Linux 3.0)
- Эти часы подобны CLOCK_BOOTTIME, но разбудят систему, если она находится с состоянии ожидания. Для установки таймера по этим часам вызывающий должен иметь мандат CAP_WAKE_ALARM.
- CLOCK_TAI (начиная с Linux 3.10)
- A system-wide clock derived from wall-clock time but ignoring leap seconds.
- SIGEV_NONE
- Выполнять синхронное уведомление при срабатывании таймера. Ход таймера можно отслеживать с помощью timer_gettime(2).
- SIGEV_SIGNAL
- При срабатывании таймера генерировать для процесса сигнал sigev_signo. Подробности смотрите в sigevent(7). Полю si_code структуры siginfo_t присваивается значение SI_TIMER. В любой момент времени для таймера в очередь процесса ставится не более одного сигнала; подробности смотрите в timer_getoverrun(2).
- SIGEV_THREAD
- При срабатывании вызвать sigev_notify_function, как если бы это была начальная функция новой нити. Подробности смотрите в sigevent(7).
- SIGEV_THREAD_ID (есть только в Linux)
- Как для SIGEV_SIGNAL, но сигнал нацелен на нить, чей ID указывается в sigev_notify_thread_id, который должен быть нитью того же процесса что и вызывающий. В поле sigev_notify_thread_id указывается ID ядерной нити, то есть значение, возвращаемое clone(2) или gettid(2). Этот флаг предназначен только для использования в библиотеках нитей.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении timer_create() возвращается 0 и ID нового таймера помещается в *timerid. При ошибке возвращается -1, а errno устанавливается в соответствующее значение.ОШИБКИ
- EAGAIN
- Временная ошибка, на время выделения ядром структур таймера.
- EINVAL
- Некорректный ID часов, sigev_notify, sigev_signo или sigev_notify_thread_id.
- ENOMEM
- Невозможно выделить память.
- ENOTSUP
- The kernel does not support creating a timer against this clockid.
- EPERM
- clockid was CLOCK_REALTIME_ALARM or CLOCK_BOOTTIME_ALARM but the caller did not have the CAP_WAKE_ALARM capability.
ВЕРСИИ
Данный системный вызов появился в Linux 2.6.СТАНДАРТЫ
POSIX.1-2001, POSIX.1-2008.ЗАМЕЧАНИЯ
С помощью timer_create() программа может создавать несколько интервальных таймеров. Таймеры не наследуются в потомке после fork(2), и выключаются и удаляются при execve(2). Ядро заранее выделяет «сигнал реального времени в очереди» для каждого таймера, создаваемого timer_create(). В результате, количество таймеров ограничено ресурсом RLIMIT_SIGPENDING (смотрите setrlimit(2)). Таймеры, созданные timer_create(), часто называют «(интервальными) таймерами POSIX». Программный интерфейс таймеров POSIX состоит из следующих интерфейсов:- timer_create()
- Create a timer.
- timer_settime(2)
- Arm (start) or disarm (stop) a timer.
- timer_gettime(2)
- Fetch the time remaining until the next expiration of a timer, along with the interval setting of the timer.
- timer_getoverrun(2)
- Return the overrun count for the last timer expiration.
- timer_delete(2)
- Disarm and delete a timer.
Отличия между библиотекой C и ядром
Частично, реализация программного интерфейса таймеров POSIX предоставляется glibc. А именно:- •
- Большая часть функций для SIGEV_THREAD реализована в glibc, а не в ядре (это необходимо, так как в обработку уведомления вовлечена нить, которая должна управляться библиотекой C, реализующей нити POSIX). Хотя уведомление доставляется процессу через нить, внутри реализации NPTL для SIGEV_THREAD_ID используется значение sigev_notify и сигнал реального времени, который зарезервирован для реализации (смотрите nptl(7)).
- •
- Стандартная ситуация, когда evp равно NULL, обрабатывается в glibc, где вызывается нижележащий системный вызов с заполненной подходящим образом структурой sigevent.
- •
- Идентификаторы таймеров, обрабатываемые на уровне пользователя, поддерживаются glibc, которая отображает эти ID в ID таймеров, созданных ядром.
ПРИМЕРЫ
Программа ниже обрабатывает два аргумента: интервал сна в секундах и частоту таймера в наносекундах. Программа устанавливает обработчик сигнала для таймера, блокирует этот сигнал, создаёт и включает таймер, который срабатывает с заданной частотой, засыпает на указанное количество секунд, а после разблокирует сигнал таймера. Предполагая, что таймер сработает не менее одного раза пока программа спит, обработчик сигнала будет вызван и покажет некоторую информацию об уведомлении таймера. Программа завершается после одного вызова обработчика сигнала. В следующем примере программа спит 1 секунду после создания таймера, который работает с частотой 100 наносекунд. За время разблокировки и доставки сигнала, произошло около 10 миллионов переполнений../$ ./a.out 1 100 Устанавливается обработчик сигнала 34 Блокируется сигнал 34 ID таймера — 0x804c008 Спим 1 секунду Разблокируется сигнал 34 Пойман сигнал 34 sival_ptr = 0xbfb174f4; *sival_ptr = 0x804c008 счётчик переполнения = 10004886
Исходный код программы
#include <signal.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #define CLOCKID CLOCK_REALTIME #define SIG SIGRTMIN #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void print_siginfo(siginfo_t *si) { int or; timer_t *tidp; tidp = si->si_value.sival_ptr; printf(" sival_ptr = %p; ", si->si_value.sival_ptr); printf(" *sival_ptr = %#jx\n", (uintmax_t) *tidp); or = timer_getoverrun(*tidp); if (or == -1) errExit("timer_getoverrun"); else printf(" счётчик переполнения = %d\n", or); } static void handler(int sig, siginfo_t *si, void *uc) { /* Замечание: вызов printf() из обработчика сигнала небезопасен (и не должен выполняться в готовых программах), так как printf() не async-signal-safe; смотрите signal-safety(7). Тем не менее, здесь мы используем printf(), так как это простой способ показать когда вызывается обработчик. */ printf("Пойман сигнал %d\n", sig); print_siginfo(si); signal(sig, SIG_IGN); } int main(int argc, char *argv[]) { timer_t timerid; sigset_t mask; long long freq_nanosecs; struct sigevent sev; struct sigaction sa; struct itimerspec its; if (argc != 3) { fprintf(stderr, "Использование: %s <secs> <nsecs>\n", argv[0]); exit(EXIT_FAILURE); } /* Устанавливаем обработчик для сигнала таймера. */ printf("Устанавливается обработчик сигнала %d\n", SIG); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); if (sigaction(SIG, &sa, NULL) == -1) errExit("sigaction"); /* Временно блокируем сигнал таймера. */ printf("Блокируется сигнал %d\n", SIG); sigemptyset(&mask); sigaddset(&mask, SIG); if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) errExit("sigprocmask"); /* Создаём таймер. */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCKID, &sev, &timerid) == -1) errExit("timer_create"); printf("ID таймера %#jx\n", (uintmax_t) timerid); /* Запускаем таймер. */ freq_nanosecs = atoll(argv[2]); its.it_value.tv_sec = freq_nanosecs / 1000000000; its.it_value.tv_nsec = freq_nanosecs % 1000000000; its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; if (timer_settime(timerid, 0, &its, NULL) == -1) errExit("timer_settime"); /* Ненадолго засыпаем; за это время, таймер может сработать несколько раз. */ printf("Спим %d секунду\n", atoi(argv[1])); sleep(atoi(argv[1])); /* Разблокируем сигнал таймера, чтобы доставлялись уведомления таймера. */ printf("Разблокируется сигнал %d\n", SIG); if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) errExit("sigprocmask"); exit(EXIT_SUCCESS); }
СМ. ТАКЖЕ
clock_gettime(2), setitimer(2), timer_delete(2), timer_getoverrun(2), timer_settime(2), timerfd_create(2), clock_getcpuclockid(3), pthread_getcpuclockid(3), pthreads(7), sigevent(7), signal(7), time(7)ПЕРЕВОД
Русский перевод этой страницы руководства был сделан Azamat Hackimov <[email protected]>, Dmitry Bolkhovskikh <[email protected]>, Yuri Kozlov <[email protected]> и Иван Павлов <[email protected]> Этот перевод является бесплатной документацией; прочитайте Стандартную общественную лицензию GNU версии 3 или более позднюю, чтобы узнать об условиях авторского права. Мы не несем НИКАКОЙ ОТВЕТСТВЕННОСТИ. Если вы обнаружите ошибки в переводе этой страницы руководства, пожалуйста, отправьте электронное письмо на [email protected]5 февраля 2023 г. | Linux man-pages 6.03 |