Provided by: manpages-ru-dev_4.27.0-1_all bug

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

       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 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

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

Справочные страницы Linux 6.9.1                  15 июня 2024 г.                                 timer_create(2)