Loading

NOM

       timer_create - Créer une minuterie POSIX pour un processus

SYNOPSIS

       #include <signal.h>
       #include <time.h>

       int timer_create(clockid_t clockid, struct sigevent *evp,
                        timer_t *timerid);

       Effectuez l’édition des liens avec l’option -lrt.

   Exigences  de  macros  de  test  de  fonctionnalités  pour  la  glibc (voir
   feature_test_macros(7)) :

       timer_create() : _POSIX_C_SOURCE >= 199309

       timer_create()  crée  une  nouvelle  minuterie  pour   une   processus.
       L’identifiant  de  cette  nouvelle minuterie est renvoyé dans le tampon
       pointé par timerid, qui  doit  être  un  pointeur  différent  de  NULL.
       L’identifiant est unique pour le processus, jusqu’à ce que la minuterie
       soit détruite. La nouvelle minuterie est initialement désarmée.

       Le paramètre  clockid  indique  l’horloge  que  la  nouvelle  minuterie
       utilise  pour  mesurer  le  temps.  Il  peut  prendre  une  des valeurs
       suivantes :

       CLOCK_REALTIME
              Une horloge système temps réel configurable.

       CLOCK_MONOTONIC
              Une horloge non configurable, toujours croissante qui mesure  le
              temps  depuis  un  instant  non spécifié dans le passé et qui ne
              change pas après le démarrage du système.

       CLOCK_PROCESS_CPUTIME_ID (depuis Linux 2.6.12)
              Une horloge qui mesure le temps  CPU  (utilisateur  et  système)
              consommé par le processus appelant (et tous ses threads).

       CLOCK_THREAD_CPUTIME_ID (depuis Linux 2.6.12)
              Une  horloge  qui  mesure  le temps CPU (utilisateur et système)
              consommé par le processus appelant.

       Comme pour les  valeurs  ci-dessus,  clockid  peut  être  l’identifiant
       clockid    renvoyé   par   un   appel   à   clock_getcpuclockid(3)   ou
       pthread_getcpuclockid(3).

       Le paramètre evp pointe vers une structure sigevent qui indique comment
       l’appelant  devrait  être  notifié  quand  la  minuterie  expire. Cette
       structure est environ définie comme ceci :

           union sigval {
               int   sival_int;
               void *sival_ptr;
           };

           struct sigevent {
               int          sigev_notify;    /* Méthode de notification */
               int          sigev_signo;     /* Signal d’expiration de
                                                la minuterie */
               union sigval sigev_value;     /* Valeur accompagnant le signal
                                                ou étant fournie à la fonction
                                                du thread */
               void       (*sigev_notify_function) (union sigval);
                              /* Fonction utilisée pour la notification
                                 d’un thread (SIGEV_THREAD) */
               void        *sigev_notify_attributes;
                              /* Paramètres pour la notification d’un thread
                                 (SIGEV_THREAD) */
               pid_t        sigev_notify_thread_id;
                              /* Identifiant du thread auquel est envoyé
                                 un signal (SIGEV_THREAD_ID) */
           };

       Certains de ces champs  font  partie  d’une  union :  un  programme  ne
       devrait utiliser que les champs appropriés pour la valeur indiquée dans
       sigev_notify. Ce champ peut avoir les valeurs suivantes :

       SIGEV_NONE
              Ne pas notifier de façon asynchrone quand la  minuterie  expire.
              La  progression  de la minuterie peut être observée en utilisant
              timer_gettime(2).

       SIGEV_SIGNAL
              Lors  de  l’expiration  de  la  minuterie,  produire  le  signal
              sigev_signo  pour  le  processus.  Si  sigev_signo est un signal
              temps réel, alors il sera accompagné par les  données  indiquées
              dans  sigev_value  (en  tant  que données accompagnant le signal
              pour sigqueue(2)). À tout moment, au plus un signal est  mis  en
              attente  pour  le  processus pour une horloge donnée ; consultez
              timer_getoverrun(2) pour plus de détails.

       SIGEV_THREAD
              Après expiration de la minuterie, appeler  sigev_notify_function
              comme  s’il  s’agissait de la fonction de démarrage d’un nouveau
              thread (il y a plusieurs possibilités d’implémentation, dont  la
              création   d’un  nouveau  thread  pour  chaque  notification  de
              minuterie, ou la création d’un unique thread pour  la  réception
              de  toutes  les  notifications).  La  fonction  est appelée avec
              sigev_value comme unique paramètre.  Si  sigev_notify_attributes
              n’est   pas   NULL,   il   doit   pointer   vers  une  structure
              pthread_attr_t qui définie les paramètres pour le nouveau thread
              (voir pthread_attr_init(3)).

       SIGEV_THREAD_ID (spécifique à Linux)
              Comme  SIGEV_SIGNAL,  mais  le  signal est envoyé au thread dont
              l’identifiant est fourni dans sigev_notify_thread_id,  qui  doit
              être  un  thread  du  même  processus que le thread appelant. Le
              champ sigev_notify_thread_id indique un  identifiant  de  thread
              noyau,   c’est-à-dire   la   valeur  renvoyée  par  clone(2)  ou
              gettid(2). Ce drapeau n’est destiné à être utilisé  que  par  la
              bibliothèque des threads.

       Une  valeur  NULL  pour  evp  équivaut  à indiquer un pointeur vers une
       structure  sigevent  dans  laquelle  sigev_notify  vaut   SIGEV_SIGNAL,
       sigev_signo vaut SIGALRM et sigev_value.sival_int vaut l’identifiant de
       l’horloge.

VALEUR RENVOYÉE

       S’il réussit,  timer_create()  renvoie  zéro  et  l’identifiant  de  la
       nouvelle minuterie est placé dans *timerid. En cas d’erreur, il renvoie
       -1 et errno contient le code d’erreur.

ERREURS

       EAGAIN Erreur temporaire lors de l’allocation de  la  structure  de  la
              minuterie par le noyau.

       EINVAL L’identifiant    d’horloge,    sigev_notify,    sigev_signo   ou
              sigev_notify_thread_id n’est pas valable.

       ENOMEM Impossible d’allouer de la mémoire.

VERSIONS

       Cet appel système est disponible depuis Linux 2.6.

CONFORMITÉ

       POSIX.1-2001

NOTES

       Un   programme   peut   créer   plusieurs   minuterie   en    utilisant
       timer_create().

       Les  minuteries  ne sont pas héritées par ses enfants lors d’un fork(2)
       et sont désarmées et détruites lors d’un appel système execve(2).

       Le noyau alloue par avance un « signal temps  réel  en  attente »  pour
       chaque  minuterie  créée  par  timer_create(). De ce fait, le nombre de
       minuteries est limité par la  limite  de  ressources  RLIMIT_SIGPENDING
       (voir setrlimit(2)).

       Les  minuteries  créée  par  timer_create()  sont  communément appelées
       « horloges (d’intervalle)  POSIX ».  L’API  des  minuteries  POSIX  est
       constituée des interfaces suivantes :

       *  timer_create() : Créer une minuterie.

       *  timer_settime(2) :   Armer  (démarrer)  ou  désarmer  (stopper)  une
          minuterie.

       *  timer_gettime(2) : Récupérer le temps restant  jusqu’à  l’expiration
          suivante d’une minuterie, en plus de l’intervalle de la minuterie.

       *  timer_getoverrun(2) :  Renvoyer  le décompte de dépassements pour la
          dernière expiration de la minuterie.

       *  timer_delete(2) : Désarmer et détruire une minuterie.

       Une partie de l’implémentation des minuteries POSIX est fournie par  la
       glibc. En particulier :

       *  La  fonctionnalité  de  SIGEV_THREAD  est implémentée dans la glibc,
          plutôt que par le noyau.

       *  Les identifiants de minuteries fournis au  niveau  utilisateur  sont
          maintenus  par  la  glibc,  qui  fait  la  correspondance  avec  les
          identifiants utilisés par le noyau.

       Les appels système pour les  minuteries  POSIX  sont  apparus  dans  le
       noyaux  Linux 2.6.  Auparavant, la glibc fournissait une implémentation
       incomplète  en  espace  utilisateur  (les   minuteries   CLOCK_REALTIME
       uniquement)  en  utilisant  les  threads  POSIX,  et  la glibc actuelle
       utilise toujours cette implémentation sur les systèmes ayant  un  noyau
       antérieur au noyau Linux 2.6.

EXEMPLE

       Le  programme ci-dessous reçoit deux paramètres : une durée de sommeil,
       en seconde, et une fréquence de minuterie en nanosecondes. Le programme
       établit un gestionnaire pour le signal qu’il utilise avec la minuterie,
       puis il bloque le signal, crée et arme une minuterie qui  expire  à  la
       fréquence  donnée, s’endort pendant la durée indiquée et enfin débloque
       le signal de la minuterie. En supposant que la minuterie ait expiré  au
       moins  une  fois  pendant  le  sommeil du programme, le gestionnaire de
       signal sera appelé et le gestionnaire de signal affiche des information
       concernant  la  notification  de  la minuterie. Le programme se termine
       après un appel au gestionnaire de signal.

       Dans l’exemple d’exécution qui suit, le  programme  s’endort  pour  une
       seconde  après  avoir  créé  une  minuterie  de  d’une fréquence de 100
       nanosecondes. Le temps que le signal soit débloqué et fournit, il  y  a
       eu environ dix millions de dépassements.

           $ ./a.out 1 10
           Establishing handler for signal 34
           Blocking signal 34
           timer ID is 0x804c008
           Sleeping for 1 seconds
           Unblocking signal 34
           Caught signal 34
               sival_ptr = 0xbfb174f4;     *sival_ptr = 0x804c008
               overrun count = 10004886

   Source du programme

       #include <stdlib.h>
       #include <unistd.h>
       #include <stdio.h>
       #include <signal.h>
       #include <time.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)
       {
           timer_t *tidp;
           int or;

           tidp = si->si_value.sival_ptr;

           printf("    sival_ptr = %p; ", si->si_value.sival_ptr);
           printf("    *sival_ptr = 0x%lx\n", (long) *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
              strictly correct, since printf() is not async-signal-safe;
              see signal(7) */

           printf("Caught signal %d\n", sig);
           print_siginfo(si);
           signal(sig, SIG_IGN);
       }

       int
       main(int argc, char *argv[])
       {
           timer_t timerid;
           struct sigevent sev;
           struct itimerspec its;
           long long freq_nanosecs;
           sigset_t mask;
           struct sigaction sa;

           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 0x%lx\n", (long) 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);
       }

VOIR AUSSI

       clock_gettime(2),   setitimer(2),   timer_delete(2),  timer_settime(2),
       timer_getoverrun(2),     timerfd_create(2),     clock_getcpuclockid(3),
       pthread_getcpuclockid(3), pthreads(7), signal(7), time(7)

COLOPHON

       Cette  page  fait  partie  de  la  publication 3.23 du projet man-pages
       Linux. Une description du projet et des instructions pour signaler  des
       anomalies       peuvent       être       trouvées      à      l’adresse
       http://www.kernel.org/doc/man-pages/.

TRADUCTION

       Cette page de manuel a  été  traduite  et  est  maintenue  par  Nicolas
       François  <nicolas.francois@centraliens.net> et l’équipe francophone de
       traduction de Debian.

       Veuillez  signaler  toute  erreur   de   traduction   en   écrivant   à
       <debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
       paquet manpages-fr.

       Vous pouvez toujours avoir accès à la version anglaise de  ce  document
       en utilisant la commande « man -L C <section> <page_de_man> ».