Man page - timer_create(2)

Packages contains this manual

Available languages:

en fr ru

Manual

timer_create

НАИМЕНОВАНИЕ
БИБЛИОТЕКА
ОБЗОР
ОПИСАНИЕ
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
ОШИБКИ
ВЕРСИИ
Отличия между библиотекой C и ядром
СТАНДАРТЫ
ИСТОРИЯ
ПРИМЕЧАНИЯ
ПРИМЕРЫ
Исходный код программы
СМОТРИТЕ ТАКЖЕ
ПЕРЕВОД

НАИМЕНОВАНИЕ

timer_create - создаёт таймер POSIX для определённого процесса

БИБЛИОТЕКА

Библиотека реального времени ( 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)

Системные часы, основанные на времени настенных часов, но учитывающие дополнительные секунды.

See clock_getres (2) for some further details on the above clocks.

Помимо значений, перечисленных ранее, в clockid может быть указано clockid , возвращённое вызовом clock_getcpuclockid (3) или pthread_getcpuclockid (3).

The sevp argument points to a sigevent structure that specifies how the caller should be notified when the timer expires. For the definition and general details of this structure, see sigevent (3type).

В поле sevp.sigev_notify можно указать следующие значения:
SIGEV_NONE

Выполнять синхронное уведомление при срабатывании таймера. Ход таймера можно отслеживать с помощью timer_gettime (2).

SIGEV_SIGNAL

Upon timer expiration, generate the signal sigev_signo for the process. See sigevent (3type) for general details. The si_code field of the siginfo_t structure will be set to SI_TIMER . At any point in time, at most one signal is queued to the process for a given timer; see timer_getoverrun (2) for more details.

SIGEV_THREAD

Upon timer expiration, invoke sigev_notify_function as if it were the start function of a new thread. See sigevent (3type) for details.

SIGEV_THREAD_ID (есть только в Linux)

Как для SIGEV_SIGNAL , но сигнал нацелен на нить, чей ID указывается в sigev_notify_thread_id , который должен быть нитью того же процесса что и вызывающий. В поле sigev_notify_thread_id указывается ID ядерной нити, то есть значение, возвращаемое clone (2) или gettid (2). Этот флаг предназначен только для использования в библиотеках нитей.

Указание в sevp значения NULL эквивалентно указанию указателя на структуру sigevent , в которой sigev_notify равно SIGEV_SIGNAL , sigev_signo равно SIGALRM и sigev_value.sival_int равно ID таймера.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении 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.

ВЕРСИИ

Отличия между библиотекой C и ядром

Частично, реализация программного интерфейса таймеров POSIX предоставляется glibc. А именно:

Большая часть функций для SIGEV_THREAD реализована в glibc, а не в ядре (это необходимо, так как в обработку уведомления вовлечена нить, которая должна управляться библиотекой C, реализующей нити POSIX). Хотя уведомление доставляется процессу через нить, внутри реализации NPTL для SIGEV_THREAD_ID используется значение sigev_notify и сигнал реального времени, который зарезервирован для реализации (смотрите nptl (7)).

Стандартная ситуация, когда evp равно NULL, обрабатывается в glibc, где вызывается нижележащий системный вызов с заполненной подходящим образом структурой sigevent .

Идентификаторы таймеров, обрабатываемые на уровне пользователя, поддерживаются glibc, которая отображает эти ID в ID таймеров, созданных ядром.

СТАНДАРТЫ

POSIX.1-2008.

ИСТОРИЯ

Linux 2.6. POSIX.1-2001.

Prior to Linux 2.6, glibc provided an incomplete user-space implementation ( CLOCK_REALTIME timers only) using POSIX threads, and before glibc 2.17, the implementation falls back to this technique on systems running kernels older than Linux 2.6.

ПРИМЕЧАНИЯ

С помощью 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.

Начиная с Linux 3.10, файл /proc/ pid /timers можно использовать для просмотра списка таймеров POSIX для процесса с PID равным pid . Подробности смотрите в proc (5).

Начиная с Linux 4.10, поддержка таймеров POSIX теперь необязательна и включена по умолчанию. Поддержку в ядре можно выключить через параметр CONFIG_POSIX_TIMERS .

ПРИМЕРЫ

Программа ниже обрабатывает два аргумента: интервал сна в секундах и частоту таймера в наносекундах. Программа устанавливает обработчик сигнала для таймера, блокирует этот сигнал, создаёт и включает таймер, который срабатывает с заданной частотой, засыпает на указанное количество секунд, а после разблокирует сигнал таймера. Предполагая, что таймер сработает не менее одного раза пока программа спит, обработчик сигнала будет вызван и покажет некоторую информацию об уведомлении таймера. Программа завершается после одного вызова обработчика сигнала.

В следующем примере программа спит 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(" overrun count = %d\n", or);
}
static void
handler(int sig, siginfo_t *si, void *uc)
{
/* Note: calling printf() from a signal handler is not safe
(and should not be done in production programs), since
printf() is not async-signal-safe; see signal-safety(7).
Nevertheless, we use printf() here as a simple way of
showing that the handler was called. */
printf("Caught signal %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, "Usage: %s <sleep-secs> <freq-nanosecs>\n",
argv[0]);
exit(EXIT_FAILURE);
}
/* Establish handler for timer signal. */
printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIG, &sa, NULL) == -1)
errExit("sigaction");
/* Block timer signal temporarily. */
printf("Blocking signal %d\n", SIG);
sigemptyset(&mask);
sigaddset(&mask, SIG);
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
errExit("sigprocmask");
/* Create the timer. */
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("timer ID is %#jx\n", (uintmax_t) timerid);
/* Start the timer. */
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");
/* Sleep for a while; meanwhile, the timer may expire
multiple times. */
printf("Sleeping for %d seconds\n", atoi(argv[1]));
sleep(atoi(argv[1]));
/* Unlock the timer signal, so that timer notification
can be delivered. */
printf("Unblocking signal %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 (3type), signal (7), time (7)

ПЕРЕВОД

Русский перевод этой страницы руководства разработал(и) Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков .