timerfd_create, timerfd_settime, timerfd_gettime - Minuteries qui informent par
l'intermédiaire de descripteurs de fichier
Bibliothèque C standard (
libc,
-lc)
#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
int timerfd_settime(int fd, int flags,
const struct itimerspec *new_value,
struct itimerspec *_Nullable old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
Ces appels système créent et opèrent sur une minuterie qui
fournit des notifications d'expiration par un descripteur de fichier. Ils
fournissent une alternative à
setitimer(2) ou
timer_create(2) avec l'avantage que le descripteur de fichier peut
être surveillé avec
select(2),
poll(2) ou
epoll(7).
L'utilisation de ces trois appels système est analogue à
l'utilisation de
timer_create(2),
timer_settime(2) et
timer_gettime(2). (Il n'y a pas d'équivalent à
timer_getoverrun(2) puisque cette fonctionnalité est fournie par
read(2), comme décrit ci-dessous)
timerfd_create() crée un nouvel objet minuterie et renvoie un
descripteur de fichier qui se réfère à cette minuterie.
Le paramètre
clockid indique l'horloge utilisée pour
marquer la progression de la minuterie qui doit être une des
suivantes :
- CLOCK_REALTIME
- Une horloge temps réel configurable à
l'échelle du système.
- 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_BOOTTIME (depuis Linux 3.15)
- C'est une horloge toujours croissante comme
CLOCK_MONOTONIC. Cependant alors que l'horloge
CLOCK_MONOTONIC ne mesure pas le temps aussi longtemps que le
système est suspendu, l'horloge CLOCK_BOOTTIME inclut le
temps pendant lequel le système est suspendu. Cela est utile pour
les applications qui doivent être sensibles au temps de suspension.
CLOCK_REALTIME n'est pas adapté à ce type
d'application dans la mesure où cette horloge est affectée
par des modifications discontinues de l'horloge système.
-
CLOCK_REALTIME_ALARM (depuis Linux 3.11)
- Cette horloge se comporte comme CLOCK_REALTIME, mais
réveillera le système s'il est suspendu. L'appelant doit
avoir la capacité CAP_WAKE_ALARM afin de régler une
minuterie utilisant cette horloge.
-
CLOCK_BOOTTIME_ALARM (depuis Linux 3.11)
- Cette horloge se comporte comme CLOCK_BOOTTIME, mais
réveillera le système s'il est suspendu. L'appelant doit
avoir la capacité CAP_WAKE_ALARM afin de régler une
minuterie utilisant cette horloge.
Consultez
clock_getres(2) pour quelques détails
supplémentaires sur les horloges mentionnées.
La valeur actuelle de chacune de ces horloges peut être obtenue avec
clock_gettime(2).
À partir de Linux 2.6.27, les valeurs suivantes peuvent être
incluses avec un OU binaire dans
flags pour changer le comportement de
timerfd_create() :
- TFD_NONBLOCK
- Placer l'attribut d'état de fichier
O_NONBLOCK sur la description du fichier ouvert
référencée par le nouveau descripteur de fichier
(consulter open(2)). Utiliser cet attribut économise des
appels supplémentaires à fcntl(2) pour obtenir le
même résultat.
- TFD_CLOEXEC
- Placer l'attribut
« close-on-exec » ( FD_CLOEXEC) sur le
nouveau descripteur de fichier. Consultez la description de l'attribut
O_CLOEXEC dans open(2) pour savoir pourquoi cela peut
être utile.
Dans les versions de Linux jusqu'à la version 2.6.26 incluse,
flags doit être nul.
timerfd_settime() arme (démarre) ou désarme (stoppe) la
minuterie à laquelle se réfère le descripteur de fichier
fd.
Le paramètre
new_value spécifie l'expiration initiale et
l'intervalle de la minuterie. La structure
itimerspec utilisée
pour ce paramètre est décrite dans
itimerspec(3type) :
new_value.it_value spécifie l'expiration initiale de la minuterie,
en secondes et nanosecondes. Une valeur non nulle dans un des champs de
new_value.it_value arme la minuterie. La minuterie est
désarmée si les deux champs de
new_value.it_value sont
mis à zéro.
Une valeur non nulle dans un des champs de
new_value.it_interval
configure la période, en secondes et nanosecondes, pour une expiration
répétitive après l'expiration initiale. Si les deux
champs de
new_value.it_interval sont nuls, la minuterie expirera qu'une
seule fois, dont l'heure est spécifiée dans
new_value.it_value.
Par défaut, l'heure d'expiration initiale spécifiée dans
new_value est interprétée de façon relative par
rapport à l'heure actuelle sur l'horloge de la minuterie au moment de
l'appel (c'est-à-dire que
new_value.it_value indique une heure
relative à la valeur actuelle de l'horloge spécifiée par
clockid). Un délai absolu peut être
sélectionné avec le paramètre
flags.
Le paramètre
flags est un masque de bits qui peut avoir les
valeurs suivantes :
- TFD_TIMER_ABSTIME
- Interpréter new_value.it_value comme une
valeur absolue sur l'horloge de la minuterie. La minuterie expirera quand
la valeur de l'horloge de la minuterie atteint la valeur
spécifiée dans new_value.it_value.
- TFD_TIMER_CANCEL_ON_SET
- Si cet attribut est spécifié en même
temps que TFD_TIMER_ABSTIME et si l'horloge pour cette minuterie
est CLOCK_REALTIME ou CLOCK_REALTIME_ALARM, alors marquer
cette minuterie comme annulable si l'horloge en temps réel subit
une modification discontinue ( settimeofday(2),
clock_settime(2) ou similaire). Quand des modifications se
produisent, un appel actuel ou futur à read(2) à
partir du descripteur de fichier échouera avec l’erreur
ECANCELED.
Si le paramètre
old_value n'est pas égal à NULL, la
structure
itimerspec vers laquelle il pointe est utilisée pour
renvoyer la configuration de la minuterie au moment de l'appel ;
consultez la description de
timerfd_gettime() ci-dessous.
timerfd_gettime() renvoie, dans
curr_value, une structure
itimerspec qui contient les paramètres actuels de la minuterie
auquel le descripteur de fichier
fd fait référence.
Le champ
it_value renvoie la durée jusqu'à la prochaine
expiration. Si les deux champs de cette structure sont nuls, alors la
minuterie est actuellement désactivée. Ce champ contient
toujours une valeur relative, sans tenir compte d'un attribut
TFD_TIMER_ABSTIME qui aurait été spécifié
quand la minuterie a été configurée.
Le champ
it_interval renvoie l'intervalle de la minuterie. Si les deux
champs de cette structure sont nuls, alors la minuteries est configurée
pour n'expirer qu'une seule fois, à l'heure spécifiée par
curr_value.it_value.
Le descripteur de fichier renvoyé par
timerfd_create() gère
les opérations supplémentaires suivantes :
-
read(2)
- Si la minuterie a déjà expirée une
fois ou plus depuis que sa configuration a été
modifiée la dernière fois à l'aide de
timerfd_settime() ou depuis la dernière lecture avec
read(2) qui a réussi, alors le tampon fourni à
read(2) renvoie un entier non signé sur 8 octets (
uint64_t) qui contient le nombre d'expirations qui se sont
produites. (La valeur renvoyée utilise l'ordre des octets de
l'hôte, c'est-à-dire l'ordre des octets natif pour les
entiers sur la machine hôte.)
- Si aucune expiration ne s'est produite au moment de l'appel
à read(2), l'appel bloquera jusqu'à la prochaine
expiration ou échouera avec l'erreur EAGAIN si le
descripteur de fichier est en mode non bloquant (à l'aide de de
l'opération F_SETFL de fcntl(2) pour régler
l'attribut O_NONBLOCK).
- Un read(2) échouera avec l'erreur
EINVAL si la taille du tampon fourni est de moins de
8 octets.
- Si l'horloge associée est soit CLOCK_REALTIME
ou CLOCK_REALTIME_ALARM, si la minuterie est absolue (
TFD_TIMER_ABSTIME) et si l'attribut TFD_TIMER_CANCEL_ON_SET
a été spécifié lors de l'appel
timerfd_settime(), alors l'appel à read(2)
échoue avec l'erreur ECANCELED si l'horloge en temps
réel subit une modification discontinue. (Cela permet à
l'application qui lit de découvrir ce type de modifications
discontinues à l'horloge.)
- Si l'horloge associée est soit CLOCK_REALTIME
ou CLOCK_REALTIME_ALARM, si la minuterie est absolue (
TFD_TIMER_ABSTIME) et si l'attribut TFD_TIMER_CANCEL_ON_SET
a été spécifié lors de l'appel
timerfd_settime(), alors une modification négative
discontinue à l'horloge (par exemple, clock_settime(2)) peut
faire à que read(2) supprime le blocage, mais renvoie une
valeur de 0 (c'est-à-dire qu'aucun octet n'est lu), si une
modification d'horloge survient après que le temps soit
expiré, mais avant le read(2) sur le descripteur de
fichier.
-
poll(2), select(2) (et similaire)
- Le descripteur de fichier est lisible (le paramètre
readfds de select(2) ; l'attribut POLLIN de
poll(2)) si une expiration (ou plus) de la minuterie s'est
produite.
- Le descripteur de fichier prend également en charge
les autres interfaces de multiplexage de descripteurs de fichier :
pselect(2), ppoll(2) et epoll(7).
-
ioctl(2)
- La commande suivante spécifique à timerfd est
prise en charge :
-
TFD_IOC_SET_TICKS (depuis Linux 3.17)
- Ajuste le nombre d'expirations de minuterie qui sont
survenues. Le paramètre est un pointeur vers un entier de
8 octets différent de zéro ( uint64_t*)
contenant le nouveau nombre d'expirations. Une fois que le nombre est
défini, tout processus en attente de la minuterie est
réveillé. Le seul objectif de cette commande est de
rétablir les expirations dans l'objectif de points de
vérification ou de restauration. Cette opération est
disponible seulement si le noyau a été configuré avec
l'option CONFIG_CHECKPOINT_RESTORE.
-
close(2)
- Quand le descripteur de fichier n'est plus
nécessaire il doit être fermé. Quand tous les
descripteurs de fichier associés au même objet minuterie ont
été fermés, la minuterie est désarmée
et ses ressources sont libérées par le noyau.
Après un
fork(2), l'enfant hérite d'une copie du
descripteur de fichier créé par
timerfd_create(). Le
descripteur de fichier se réfère au même objet minuterie
sous-jacent que le descripteur de fichier correspondant dans le parent, et un
read(2) de l'enfant renverra les informations sur les expirations de la
minuterie.
Un descripteur de fichier créé par
timerfd_create() est
conservé au travers d'un
execve(2), et continue à
générer des expirations de minuterie si la minuterie a
été armée.
S'il réussit,
timerfd_create() renvoie un nouveau descripteur de
fichier. En cas d'erreur, il renvoie
-1 et
errno est
défini pour indiquer l'erreur.
En cas de réussite,
timerfd_settime() et
timerfd_gettime()
renvoient
0. Sinon ils renvoient
-1 et définissent
errno pour indiquer l'erreur.
timerfd_create() peut échouer avec les erreurs suivantes :
- EINVAL
- Le clockid n'est pas valable.
- EINVAL
-
flags n'est pas correct ; ou, pour les
versions de Linux 2.6.26 ou antérieures, flags n'est
pas nul.
- EMFILE
- La limite du nombre de descripteurs de fichiers par
processus a été atteinte.
- ENFILE
- La limite du nombre total de fichiers ouverts pour le
système entier a été atteinte.
- ENODEV
- Impossible de monter (en interne) le
périphérique anonyme d'inœud.
- ENOMEM
- Pas assez de mémoire noyau pour créer la
minuterie.
- EPERM
-
clockid était CLOCK_REALTIME_ALARM ou
CLOCK_BOOTTIME_ALARM, mais l'appelant n'a pas la capacité
CAP_WAKE_ALARM.
timerfd_settime() et
timerfd_gettime() peuvent échouer avec
les erreurs suivantes :
- EBADF
-
fd n'est pas un descripteur de fichier valable.
- EFAULT
-
new_value, old_value ou curr_value
n'est pas un pointeur valable.
- EINVAL
-
fd n'est pas un descripteur de fichier de minuterie
valable.
timerfd_settime() peut aussi échouer avec les erreurs
suivantes :
- ECANCELED
- Voir NOTES
- EINVAL
-
new_value n'est pas initialisé correctement
(un des champs tv_nsec est en dehors de l'intervalle allant de 0
à 999 999 999).
- EINVAL
-
flags n'est pas correct.
Ces appels système sont disponibles depuis Linux 2.6.25. La prise
en charge de la bibliothèque est fournie depuis la glibc 2.8.
Ces appels système sont spécifiques à Linux.
En supposant le scénario suivant pour une minuterie
CLOCK_REALTIME
ou
CLOCK_REALTIME_ALARM créée avec
timerfd_create() :
- (1)
- la minuterie a été démarrée
(timerfd_settime()) avec les attributs TFD_TIMER_ABSTIME et
TFD_TIMER_CANCEL_ON_SET ;
- (2)
- une modification discontinue (par exemple,
settimeofday(2)) est ensuite appliquée à l'horloge
CLOCK_REALTIME ;
- (3)
- l'appelant appelle une fois de plus
timerfd_settime() pour réarmer la minuterie (sans
exécuter préalablement un read(2) sur le descripteur
de fichier).
Dans ce cas les événements suivants se produisent :
- •
-
timerfd_settime() renvoie -1 avec
errno défini à ECANCELED. (Cela permet
à l'appelant de savoir que la minuterie précédente a
été affectée par une modification discontinue de
l'horloge.)
- •
- La minuterie est réarmée avec
succès avec les réglages fournis dans le second appel
timerfd_settime(). (C'est probablement un accident
d'implémentation, mais ne sera pas corrigé maintenant au cas
où des applications dépendent de ce comportement.)
Actuellement,
timerfd_create() prend en charge moins de types
d'identifiant d'horloges que
timer_create(2).
Le programme suivant crée une minuterie puis surveille sa progression. Le
programme accepte jusqu'à trois paramètres en ligne de commande.
Le premier paramètre spécifie le nombre de secondes pour
l'expiration initiale de la minuterie. Le deuxième paramètre
spécifie l'intervallse de la minuterie, en secondes. Le
troisième paramètre spécifie le nombre de fois que le
programme doit permettre à la minuterie d'expirer avant de quitter. Le
deuxième et le troisième paramètre sont optionnels.
La session interactive suivante montre l'utilisation de ce programme :
$ a.out 3 1 100
0.000: timer started
3.000: read: 1; total=1
4.000: read: 1; total=2
^Z # entrer Ctrl-Z pour suspendre le programme
[1]+ Stopped ./timerfd3_demo 3 1 100
$ fg # Reprendre l'exécution après quelques secondes
a.out 3 1 100
9.660: read: 5; total=7
10.000: read: 1; total=8
11.000: read: 1; total=9
^C # entrer Ctrl-C pour suspendre le programme
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
static void
print_elapsed_time(void)
{
int secs, nsecs;
static int first_call = 1;
struct timespec curr;
static struct timespec start;
if (first_call) {
first_call = 0;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
err(EXIT_FAILURE, "clock_gettime");
}
if (clock_gettime(CLOCK_MONOTONIC, &curr) == -1)
err(EXIT_FAILURE, "clock_gettime");
secs = curr.tv_sec - start.tv_sec;
nsecs = curr.tv_nsec - start.tv_nsec;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
printf("%d.%03d: ", secs, (nsecs + 500000) / 1000000);
}
int
main(int argc, char *argv[])
{
int fd;
ssize_t s;
uint64_t exp, tot_exp, max_exp;
struct timespec now;
struct itimerspec new_value;
if (argc != 2 && argc != 4) {
fprintf(stderr, "%s init-secs [interval-secs max-exp]\n",
argv[0]);
exit(EXIT_FAILURE);
}
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
err(EXIT_FAILURE, "clock_gettime");
/* Créer une minuterie absolue CLOCK_REALTIME avec une expiration
et un intervalle initiaux comme spécifié en ligne de commande. */
new_value.it_value.tv_sec = now.tv_sec + atoi(argv[1]);
new_value.it_value.tv_nsec = now.tv_nsec;
if (argc == 2) {
new_value.it_interval.tv_sec = 0;
max_exp = 1;
} else {
new_value.it_interval.tv_sec = atoi(argv[2]);
max_exp = atoi(argv[3]);
}
new_value.it_interval.tv_nsec = 0;
fd = timerfd_create(CLOCK_REALTIME, 0);
if (fd == -1)
err(EXIT_FAILURE, "timerfd_create");
if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &new_value, NULL) == -1)
err(EXIT_FAILURE, "timerfd_settime");
print_elapsed_time();
printf("timer started\n");
for (tot_exp = 0; tot_exp < max_exp;) {
s = read(fd, &exp, sizeof(uint64_t));
if (s != sizeof(uint64_t))
err(EXIT_FAILURE, "read");
tot_exp += exp;
print_elapsed_time();
printf("read: %" PRIu64 "; total=%" PRIu64 "\n", exp, tot_exp);
}
exit(EXIT_SUCCESS);
}
eventfd(2),
poll(2),
read(2),
select(2),
setitimer(2),
signalfd(2),
timer_create(2),
timer_gettime(2),
timer_settime(2),
timespec(3),
epoll(7),
time(7)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]>,
Cédric Boutillier <
[email protected]>,
Frédéric Hantrais <
[email protected]> et Jean-Pierre
Giraud <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 concernant les conditions de copie
et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
[email protected]