eventfd - Créer un descripteur de fichier pour la notification
d'événements
Bibliothèque C standard (
libc,
-lc)
#include <sys/eventfd.h>
int eventfd(unsigned int initval, int flags);
eventfd() créée un « objet
eventfd » qui peut être utilisé par les
applications de l'espace utilisateur pour l'attente ou la notification d'un
événement et par le noyau pour notifier des applications de
certains événements. Les objets contiennent un compteur entier
non signé sur 64 bits (
uint64_t) qui est maintenu par le
noyau. Ce compteur est initialisé à la valeur
spécifiée par le paramètre
initval.
Comme valeur de retour,
eventfd() renvoie un nouveau descripteur de
fichier qui peut être utilisé pour se référer
à l'objet eventfd.
Les valeurs suivantes peuvent être incluses (avec un OU logique) dans
flags pour changer le comportement de
eventfd() :
-
EFD_CLOEXEC (depuis Linux 2.6.27)
- 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.
-
EFD_NONBLOCK (depuis Linux 2.6.27)
- 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.
-
EFD_SEMAPHORE (depuis Linux 2.6.30)
- Fournir une sémantique similaire aux
sémaphores pour les lectures sur le nouveau descripteur de fichier.
Voir ci-dessous.
Jusqu'à Linux 2.6.26, le paramètre
flags n'est pas
utilisé et doit valoir zéro.
Les opérations suivantes peuvent être effectuées sur le
descripteur de fichier renvoyé par
eventfd() :
-
read(2)
- Chaque read(2) qui réussit renvoie un entier
sur 8 octets. read(2) échouera avec l'erreur EINVAL
si la taille du tampon fourni est de moins de 8 octets.
- La valeur renvoyée par read(2) 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.
- La sémantique de read(2) dépend du
fait que le compteur eventfd a actuellement une valeur non nulle, et que
l'attribut EFD_SEMAPHORE était spécifié lors
de la création du descripteur de fichier eventfd :
- •
- Si EFD_SEMAPHORE n'était pas
spécifié et si le compteur eventfd a une valeur non nulle,
un read(2) renverra 8 octets contenant cette valeur, et la valeur
du compteur sera remise à zéro.
- •
- Si EFD_SEMAPHORE était spécifié
et si le compteur eventfd a une valeur non nulle, un read(2)
renverra 8 octets contenant la valeur 1, et la valeur du compteur sera
décrémentée de 1.
- •
- Si le compteur eventfd est nul au moment de l'appel
à read(2), l'appel bloquera jusqu'à ce que le
compteur devienne non nul (auquel cas l'appel à read(2) sera
traité comme décrit ci-dessus), ou échouera avec
l'erreur EAGAIN si le descripteur de fichier est en mode non
bloquant.
-
write(2)
- Un appel à write(2) ajoute au compteur la
valeur de l'entier sur 8 octets fourni dans le tampon. La valeur maximale
qui peut être stockée dans le compteur est le plus grand
entier non signé sur 64 bits moins 1 (c'est-à-dire
0xfffffffffffffffe). Si l'addition résulte en un compteur qui
dépasserait la valeur maximale, le write(2) bloquera
jusqu'à ce qu'un read(2) soit effectué sur le
descripteur de fichier, ou échouera avec l'erreur EAGAIN si
le descripteur de fichier est en mode non bloquant.
- Un write(2) échouera avec l'erreur
EINVAL si la taille du tampon fourni est de moins de 8 octets ou si
l'on essaie d'écrire la valeur 0xffffffffffffffff.
-
poll(2), select(2) (et similaire)
- Le descripteur de fichier prend en charge les
poll(2) (et de façon analogue epoll(7)) et
select(2) de la façon suivante :
- •
- Le descripteur de fichier est lisible (le paramètre
readfds de select(2) ; l'attribut POLLIN de
poll(2)) si le compteur a une valeur supérieure à
0.
- •
- Le descripteur de fichier est disponible en écriture
(le paramètre writefds de select(2) ;
l'attribut POLLOUT de poll(2)) s'il est possible
d'écrire une valeur d'au moins « 1 »
sans bloquer.
- •
- Si un dépassement de la valeur du compteur a
été détectée, select(2) indique que le
descripteur de fichier est disponible en lecture et en écriture et
poll(2) renvoie un événement POLLERR. Comme
indiquée ci-dessus, un write(2) ne peut jamais produire de
dépassement. Cependant, un dépassement peut se produire si
un « signal post » eventfd de 2^64 a
été effectué par le sous-système KAIO
(théoriquement possible, mais très peut probable en
pratique). Si un dépassement survient, un read(2) renverra
la valeur maximale d'un uint64_t (c'est-à-dire
0xffffffffffffffff).
- Le descripteur de fichier eventfd prend également en
charge les autres interfaces de multiplexage de descripteurs de
fichier : pselect(2) et ppoll(2).
-
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 eventfd ont
été fermés, les ressources pour cet objet sont
libérées par le noyau.
Une copie d'un descripteur de fichier créé par
eventfd()
est héritée par le fils produit par
fork(2). Le duplicata
du descripteur de fichier est associé au même objet eventfd. Les
descripteurs de fichier créés par
eventfd() sont
préservés au travers des exécutions par
execve(2),
sauf si l'attribut « close‐on‐exec »
est positionné.
S'il réussit,
eventfd() renvoie un nouveau descripteur de fichier
eventfd. En cas d'erreur, il renvoie -1 et remplit
errno avec la valeur
d'erreur.
- EINVAL
- Une valeur non prise en compte a été
spécifiée dans flags.
- 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
- Il n'y a pas assez de mémoire pour que le noyau
crée le nouveau descripteur de fichier eventfd.
eventfd() est disponible depuis Linux 2.6.22. Une prise en charge
fonctionnelle est fournie depuis la glibc 2.8. L'appel système
eventfd2() (consultez les NOTES) est disponible sous Linux depuis
Linux 2.6.27. Depuis la glibc 2.9, la fonction enveloppe de la
glibc pour
eventfd() utilise l'appel système
eventfd2()
s'il est pris en charge par le noyau.
Pour une explication des termes utilisés dans cette section, consulter
attributes(7).
Interface |
Attribut |
Valeur |
eventfd() |
Sécurité des threads |
MT-Safe |
eventfd() et
eventfd2() sont spécifiques à Linux.
Les applications peuvent utiliser un descripteur de fichier eventfd à la
place d'un tube (consultez
pipe(2)) à chaque fois qu'un tube est
utilisé pour signaler des événements. La surcharge du
noyau pour un descripteur de fichier est bien plus faible que pour un tube. De
plus un seul descripteur de fichier est nécessaire (alors que deux sont
nécessaires pour un tube).
Quand un descripteur de fichier eventfd est utilisé par le noyau, il peut
fournir un pont entre l'espace utilisateur et l'espace noyau. Par exemple, les
fonctionnalités comme KAIO (« kernel AIO »)
pour signaler dans un descripteur de fichier que certaines opérations
sont finies.
Un aspect important d'un descripteur de fichier eventfd est qu'il peut
être surveillé comme n'importe quel descripteur de fichier avec
select(2),
poll(2) ou
epoll(7). Ceci signifie qu'une
application peut surveiller simultanément la disponibilité de
fichiers « traditionnels » et la
disponibilité de mécanismes noyau qui gèrent une
interface eventfd. (Sans l'interface
eventfd(), ces mécanismes
ne pouvaient pas être multiplexés avec
select(2),
poll(2) ou
epoll(7))
La valeur actuelle d'un compteur eventfd peut être visualisée avec
l'entrée du descripteur de fichier correspondant dans le
répertoire
/proc/pid
/fdinfo du processus. Voir
proc(5) pour plus de détails.
Il y a deux appels système sous-jacent :
eventfd() et
eventfd2(), plus récent. Le premier appel système
n'implémente pas le paramètre
flags. Le dernier appel
système implémente les valeurs de
flags décrite
ci-dessus. La fonction enveloppe de la glibc utilisera
eventfd2() quand
il est présent.
La bibliothèque C de GNU définie un type supplémentaire et
deux fonctions qui tentent d'abstraire certains détails pour la lecture
ou l'écriture avec des descripteurs de fichier eventfd :
typedef uint64_t eventfd_t;
int eventfd_read(int fd, eventfd_t *value);
int eventfd_write(int fd, eventfd_t value);
Les fonctions effectuent des actions de lecture ou écriture sur le
descripteur de fichier eventfd, en renvoyant 0 si un nombre correct d'octets a
été transféré, ou -1 sinon.
Le programme suivant crée un descripteur de fichier eventfd puis
crée un processus fils. Alors que le père commence par
s'endormir, le fils écrit tous les entiers fournis sur la ligne de
commande au descripteur de fichier eventfd. Quand le père se
réveille, il lit dans le descripteur de fichier eventfd.
La session d'interpréteur suivant montre un échantillon
d'exécution du programme :
$ ./a.out 1 2 4 7 14
Child writing 1 to efd
Child writing 2 to efd
Child writing 4 to efd
Child writing 7 to efd
Child writing 14 to efd
Child completed write loop
Parent about to read
Parent read 28 (0x1c) from efd
#include <err.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/eventfd.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int efd;
uint64_t u;
ssize_t s;
if (argc < 2) {
fprintf(stderr, "Usage: %s <num>...\n", argv[0]);
exit(EXIT_FAILURE);
}
efd = eventfd(0, 0);
if (efd == -1)
err(EXIT_FAILURE, "eventfd");
switch (fork()) {
case 0:
for (size_t j = 1; j < argc; j++) {
printf("Écriture de l'enfant %s dans efd\en", argv[j]);
u = strtoull(argv[j], NULL, 0);0
/* strtoull() autorise plusieurs bases bases */
s = write(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
err(EXIT_FAILURE,
}
printf("L'enfant a fini la boucle d'écriture\n");
exit(EXIT_SUCCESS);
default:
sleep(2);
printf(
s = read(efd, &u, sizeof(uint64_t));
if (s != sizeof(uint64_t))
err(EXIT_FAILURE, "read");
printf("Lecture du parent %"PRIu64" (%#"PRIx64") depuis efd\n", u, u);
exit(EXIT_SUCCESS);
case -1:
err(EXIT_FAILURE, "fork");
}
}
futex(2),
pipe(2),
poll(2),
read(2),
select(2),
signalfd(2),
timerfd_create(2),
write(2),
epoll(7),
sem_overview(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-Philippe
MENGUAL <
[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]