Provided by: manpages-fr_4.13-4_all bug

NOM

       epoll – Notifications d'événements d'entrées et sorties

SYNOPSIS

       #include <sys/epoll.h>

DESCRIPTION

       L'interface  de  programmation  (API)  epoll  réalise  une  tâche  similaire  à  poll(2) :
       surveiller plusieurs descripteurs de fichier pour voir si des E/S y sont possibles.  L'API
       epoll  peut  être déclenchée par changement de niveau ou par changement d'état et s'adapte
       bien à un grand nombre de descripteurs surveillés.

       Le concept central de l’API epoll est l’instance d’epoll, une structure interne  au  noyau
       qui, du point de vue espace utilisateur, peut être considérée comme un conteneur pour deux
       listes :

         •
         La liste interest (parfois appelée l’ensemble epoll) : l’ensemble  des  descripteurs  de
         fichier que le processus a enregistrés comme intéressants à surveiller.

         •
         La  liste  ready :  l’ensemble  des  descripteurs de fichier prêts (ready) pour des E/S.
         Cette liste est un sous-ensemble de (plus précisément, un  ensemble  de  références  de)
         descripteurs de fichier de la liste interest. La liste ready est alimentée dynamiquement
         par le noyau selon le résultat des activités d’E/S de ces descripteurs de fichier.

       Les appels système suivants sont fournis pour créer et gérer une instance d’epoll :

         •
         epoll_create(2)  crée  une  instance  d’epoll  et  renvoie  un  descripteur  de  fichier
         référençant  cette  instance.  La  version  plus  récente  d'epoll_create1(2)  étend les
         fonctionnalités d'epoll_create(2).

         •
         L'intérêt pour des descripteurs de fichier  particuliers  est  ensuite  enregistré  avec
         epoll_ctl(2), qui ajoute les articles dans la liste interest de l’instance d’epoll.

         •
         epoll_wait(2)  attend  les  événements  d'E/S,  en  bloquant le thread appelant si aucun
         événement n'est actuellement disponible. Cet appel système  peut  être  considéré  comme
         recherchant des articles dans la liste ready de l’instance d’epoll.

   Détection par changement de niveau ou d’état
       L'interface  de distribution d'événements d’epoll est capable de se comporter en détection
       de changement de niveau (Level  Triggered  — LT)  ou  d’état  (Edge  Triggered  — ET).  La
       différence  entre  ces  deux  mécanismes est décrite ci-dessous. Supposons que le scénario
       suivant se produise :

       1. Le descripteur de fichier qui représente le côté lecture d'un tube (rfd) est enregistré
          dans l'instance d’epoll.

       2. Une écriture dans le tube envoie 2 Ko de données du côté écriture du tube.

       3. Un appel à epoll_wait(2) est effectué et renvoie rfd comme descripteur de fichier prêt.

       4. Un lecteur du tube lit 1 Ko de données depuis rfd.

       5. Un appel d’epoll_wait(2) est effectué.

       Si  le  descripteur  rfd  a  été ajouté à l'ensemble epoll en utilisant l'attribut EPOLLET
       (détection  de  changement  d'état),  l'appel  epoll_wait(2),  réalisé  à  l'étape 5,   va
       probablement  bloquer  bien  qu'il  y  ait  des  données toujours présentes dans le tampon
       d'entrée du fichier tandis que le pair distant attendra une réponse basée sur les  données
       qu'il  a  déjà  envoyées.  La  raison en est que le mécanisme de distribution d'événements
       détectés par changement d’état délivre les événements  seulement  lorsque  des  événements
       surviennent  dans le descripteur de fichier supervisé. Ainsi, à l'étape 5, l'appelant peut
       attendre des données qui sont déjà présentes  dans  le  tampon  d'entrée.  Dans  l'exemple
       ci-dessus,  un  événement  sur  rfd  sera  déclenché  à cause de l'écriture à l'étape 2 et
       l'événement est consommé dans l’étape 3. Comme l'opération  de  lecture  de  l'étape 4  ne
       consomme  pas  toutes  les données du tampon, l'appel à epoll_wait(2) effectué à l'étape 5
       peut verrouiller indéfiniment.

       Une application qui emploie l'attribut EPOLLET  de  la  fonction  epoll  devrait  toujours
       utiliser  des descripteurs non bloquants pour éviter qu'une lecture ou une écriture affame
       une tâche qui gère plusieurs descripteurs de  fichier.  L'utilisation  préconisée  d'epoll
       comme interface en détection par changement d’état (EPOLLET) est la suivante :

       a) avec des descripteurs non bloquants ;

       b) en attente d’évènement seulement après qu'un read(2) ou un write(2) ait renvoyé EAGAIN.

       En  revanche, lorsqu'il est utilisé avec l'interface en détection par changement de niveau
       (par défaut si EPOLLET n'est pas spécifié),  epoll  est  une  alternative  plus  rapide  à
       poll(2)  et  peut être employé à chaque fois que ce dernier est utilisé, car il utilise la
       même sémantique.

       Puisque même dans un epoll de type détection le changement  d'état,  plusieurs  événements
       peuvent  être  générés  à  la  réception de nombreux blocs de données, l'appelant peut, en
       spécifiant l'attribut EPOLLONESHOT, faire désactiver par epoll le descripteur  de  fichier
       associé   après  la  réception  d'un  événement  avec  epoll_wait(2).  Lorsque  l'attribut
       EPOLLONESHOT est spécifié, il est  de  la  responsabilité  de  l'appelant  de  réarmer  le
       descripteur en utilisant epoll_ctl(2) avec EPOLL_CTL_MOD.

       Si  plusieurs  threads  (ou processus si les processus enfant ont hérité du descripteur de
       fichier d’epoll à travers fork(2)) sont bloqués dans  epoll_wait(2)  en  attente  du  même
       descripteur de fichier d’epoll et qu’un descripteur de fichier dans la liste interest, qui
       est marqué pour une notification par détection de changement  d'état  (EPOLLET),  devienne
       prêt,  seul  un des threads (ou processus) est réveillé de epoll_wait(2). Cela fournit une
       optimisation utile pour éviter la bousculade de réveils  (thundering  herd)  dans  certain
       scénarios.

   Interaction avec autosleep
       Si  le  système  est en mode autosleep à l’aide de /sys/power/autosleep et qu’un événement
       survient et sort le périphérique de sa veille, le pilote de  périphérique  ne  gardera  le
       périphérique  actif  que  jusqu’à la mise en file d’attente de l’événement. Pour garder le
       périphérique  actif   jusqu’au   traitement   de   l’événement,   l’attribut   EPOLLWAKEUP
       d’epoll_ctl(2) doit être utilisé.

       Quand  l’attribut EPOLLWAKEUP est défini dans le champ events pour une struct epoll_event,
       le système sera gardé actif à partir du moment où l’événement est mis en file d’attente, à
       l’aide  de  l’appel  epoll_wait(2)  qui  renvoie l’événement jusqu’à l’appel epoll_wait(2)
       suivant. Si l’événement doit garder le système actif  au  delà  de  ce  moment,  alors  un
       wake_lock séparé devrait être pris avant le second appel à epoll_wait(2).

   Interfaces /proc
       Les  interfaces  suivantes  peuvent  être utilisées pour limiter la quantité de mémoire du
       noyau utilisée par epoll :

       /proc/sys/fs/epoll/max_user_watches (depuis Linux 2.6.28)
              Cela définit  une  limite  au  nombre  total  de  descripteurs  de  fichiers  qu'un
              utilisateur peut enregistrer au travers de toutes les instances d’epoll du système.
              La limite est imposée par identifiant d'utilisateur  réel.  Chaque  descripteur  de
              fichier  enregistré  coûte  environ  90 octets  sur  un  noyau  32 bits  et environ
              160 octets  sur  un  noyau  64 bits.  Actuellement  la  valeur  par   défaut   pour
              max_user_watches  est  de  1/25  (4%) de la mémoire basse disponible, divisé par le
              coût d'allocation en octets.

   Exemple d'utilisation
       Tandis que l'utilisation d’epoll avec un déclenchement par changement de niveau correspond
       à la même sémantique que poll(2), le déclenchement par changement d'état nécessite plus de
       clarification pour éviter des décrochages dans la boucle  d’évènements  de  l’application.
       Dans  cet  exemple,  l’écouteur  emploie un socket non bloquant sur lequel listen(2) a été
       appelé. La fonction do_use_fd() va utiliser le nouveau descripteur de fichier  jusqu'à  ce
       qu’EAGAIN soit renvoyé par read(2) ou par write(2). Une application d’automate fini piloté
       par les évènements devrait, après réception d'EAGAIN, enregistrer l'état  en  cours,  afin
       que lors de l’appel suivant à do_use_fd(), elle continue avec le read(2) ou le write(2) là
       où elle s'est arrêtée.

           #define MAX_EVENTS 10
           struct epoll_event ev, events[MAX_EVENTS];
           int listen_sock, conn_sock, nfds, epollfd;

           /* Code pour régler le socket d’écoute, 'listen_sock',
              (socket(), bind(), listen()) omitted */

           epollfd = epoll_create1(0);
           if (epollfd == -1) {
               perror("epoll_create1");
               exit(EXIT_FAILURE);
           }

           ev.events = EPOLLIN;
           ev.data.fd = listen_sock;
           if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
               perror("epoll_ctl : listen_sock");
               exit(EXIT_FAILURE);
           }

           for (;;) {
               nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
               if (nfds == -1) {
                   perror("epoll_wait");
                   exit(EXIT_FAILURE);
               }

               for (n = 0; n < nfds; ++n) {
                   if (events[n].data.fd == listen_sock) {
                       conn_sock = accept(listen_sock,
                                          (struct sockaddr *) &addr, &addrlen);
                       if (conn_sock == -1) {
                           perror("accept");
                           exit(EXIT_FAILURE);
                       }
                       setnonblocking(conn_sock);
                       ev.events = EPOLLIN | EPOLLET;
                       ev.data.fd = conn_sock;
                       if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                                   &ev) == -1) {
                           perror("epoll_ctl: conn_sock");
                           exit(EXIT_FAILURE);
                       }
                   } else {
                       do_use_fd(events[n].data.fd);
                   }
               }
           }

       Lorsqu'on utilise une détection de changement d'états, pour des raisons  de  performances,
       il   est   possible   d'ajouter   le  descripteur  de  fichier  dans  l'interface  d’epoll
       (EPOLL_CTL_ADD) après, en spécifiant (EPOLLIN|EPOLLOUT). Cela évite de basculer sans cesse
       entre EPOLLIN et EPOLLOUT lors des appels epoll_ctl(2) avec EPOLL_CTL_MOD.

   Questions/Réponses
       0.  Quelle  est  la  clé  utilisée pour distinguer les descripteurs de fichier enregistrés
           dans une liste interest ?

           La clé est une combinaison du numéro du descripteur de fichier et de la description du
           fichier  ouvert (aussi connue comme « open file handle », la représentation interne au
           noyau d'un fichier ouvert).

       1.  Que se passe-t-il si on enregistre deux fois le même descripteur de fichier  dans  une
           instance d’epoll ?

           Vous aurez probablement un EEXIST. Cependant il est possible d'ajouter un duplicata de
           descripteur (dup(2), dup2(2), F_DUPFD de fcntl(2)) sur la même instance d’epoll.  Cela
           peut  être  une  technique  utile  pour  le filtrage d'événements, si les descripteurs
           dupliqués sont enregistrés avec des masques events différents.

       2.  Deux instances d’epoll peuvent-elles attendre le même descripteur de fichier ? Si oui,
           les événements seront-ils reportés sur les deux descripteurs de fichier d’epoll ?

           Oui, et les événements seront rapportés aux deux. Toutefois, une programmation soignée
           est nécessaire pour que cela soit fait correctement.

       3.  Est-ce que le descripteur d’epoll lui-même est sujet à poll/epoll/select ?

           Oui. Si un descripteur de fichier d’epoll  a  des  événements  en  attente,  alors  il
           indiquera qu'il est lisible.

       4.  Que  se  passe-t-il  si  on  cherche  à  placer un descripteur d’epoll dans son propre
           ensemble de descripteurs de fichier  ?

           L'appel epoll_ctl(2) échouera (EINVAL). Toutefois vous pouvez ajouter  un  descripteur
           d’epoll dans un autre ensemble de descripteurs de fichier d’epoll.

       5.  Puis-je  envoyer  le  descripteur  d’epoll  à  travers  un  socket  UNIX vers un autre
           processus ?

           Oui, mais il n'y a aucune raison de faire ça, puisque le  processus  récepteur  n'aura
           pas de copie des descripteurs de fichier de la liste interest.

       6.  Est-ce  que  la  fermeture  d'un descripteur le supprime automatiquement de toutes les
           listes interest d’epoll ?

           Oui, mais prenez note des points suivants. Un descripteur de fichier est une référence
           vers  la  description  d'un  fichier  ouvert  (consultez open(2)). À chaque fois qu'un
           descripteur est dupliqué avec dup(2), dup2(2), F_DUPFD  de  fcntl(2)  ou  fork(2),  un
           nouveau  descripteur  de  fichier  qui  se réfère au même fichier ouvert est créé. Une
           description de fichier ouvert continue d'exister jusqu'à ce que tous les  descripteurs
           de fichier qui s'y réfèrent soient fermés.

           Un  descripteur  de fichier n'est retiré d'une liste interest qu'après la fermeture de
           tous les descripteurs de fichier qui se réfèrent à la description  de  fichier  ouvert
           sous-jacente.  Cela  signifie  que même après la fermeture d'un descripteur de fichier
           faisant partie de cette liste, des événements peuvent toujours être rapportés pour  ce
           descripteur  de  fichier  si  d'autres  descripteurs de fichier, se référant à la même
           description  de  fichier  sous-jacente,  restent  ouverts.  Pour  empêcher  cela,   le
           descripteur  de  fichier  doit  être  explicitement supprimé de la liste (en utilisant
           epoll_ctl(2) EPOLL_CTL_DEL) avant qu’il ne  soit  dupliqué.  Autrement,  l’application
           doit  assurer  que  tous les descripteurs soient fermés (ce qui peut être difficile si
           les  descripteurs  ont  été  dupliqués  en  dehors  du  cadre  par  des  fonctions  de
           bibliothèque qui utilisent dup(2) ou fork(2))

       7.  Si  plus d'un événement surviennent entre deux appels epoll_wait(2), sont-ils combinés
           ou rapportés séparément ?

           Ils sont combinés.

       8.  Est-ce qu'une opération sur un descripteur affecte les événements déjà collectés  mais
           pas encore rapportés ?

           Vous pouvez faire deux choses sur un descripteur existant. Une suppression serait sans
           effet dans ce cas. Une modification revérifie les entrées et sorties disponibles.

       9.  Dois-je lire/écrire sans cesse un descripteur jusqu'à  obtenir  EAGAIN  si  l'attribut
           EPOLLET est utilisé (comportement par détection de changement d'état) ?

           La  réception  d'un  événement depuis epoll_wait(2) suggère qu'un descripteur est prêt
           pour l'opération d'E/S désirée. Il doit être considéré comme prêt jusqu'à  ce  que  la
           prochaine  lecture  ou  écriture  (non  bloquante) remonte un EAGAIN. Quand et comment
           utiliser le descripteur dépend de vous.

           Pour les fichiers orientés paquet ou jeton (par exemple, un socket  datagramme  ou  un
           terminal en mode canonique), la seule façon de détecter la fin de l'espace d'entrée et
           sortie pour les lectures ou écritures est de continuer à lire  ou  écrire  jusqu'à  la
           réception d'un EAGAIN.

           Pour  les  fichiers  orientés  flux  (par  exemple, les tubes, FIFO ou sockets en mode
           flux), la disponibilité des entrées et sorties peut aussi être détectée  en  vérifiant
           la  quantité  de  données  lues  ou  écrites  sur le descripteur. Par exemple, si vous
           appelez read(2) en demandant la lecture d'une certaine  quantité  de  données  et  que
           read(2)  en  renvoie  moins,  vous  pouvez  être  sûr  d'avoir consommé tout le tampon
           d'entrée pour le descripteur. La même chose est vraie pour  l'appel  système  write(2)
           (évitez  cette dernière technique si vous ne pouvez pas garantir que le descripteur de
           fichier surveillé corresponde toujours à un fichier de type flux).

   Erreurs possibles et moyens de les éviter
       Famine (détection par changement d'état)

       S'il y a un gros volume d’espace d’E/S, il est possible qu'en  essayant  de  les  traiter,
       d'autres  fichiers  ne  soient pas pris en compte provoquant une famine. Ce problème n'est
       pas spécifique à epoll.

       La solution est de maintenir une liste de descripteurs prêts et de marquer le  descripteur
       de  fichier  prêt dans leur structure associée, permettant à l'application de savoir quels
       fichiers traiter mais toujours en tourniquet  englobant  tous  les  fichiers  prêts.  Cela
       permet aussi d'ignorer les événements ultérieurs sur des descripteurs prêts.

       En cas d’utilisation d'un cache d'événements...

       Si  vous  utilisez  un  cache  d'événements, ou stockez tous les descripteurs renvoyés par
       epoll_wait(2), alors assurez-vous de disposer d'un moyen de  marquer  dynamiquement  leurs
       fermetures  (c’est-à-dire  causées par un traitement d’événement précédent). Supposons que
       vous recevez 100 événements d’epoll_wait(2)  et  que  l'événement 47  implique  de  fermer
       l’évènement 13. Si vous supprimez la structure et utilisez close(2) pour le descripteur de
       fichier pour l’évènement 13, alors votre cache peut encore contenir des événements pour ce
       descripteur, posant alors des problèmes de confusion.

       Une    solution    est    d'invoquer,    pendant    le   traitement   de   l'événement 47,
       epoll_ctl(EPOLL_CTL_DEL) pour supprimer le descripteur 13, le fermer avec  close(2),  puis
       marquer sa structure associée comme supprimée et la lier à une liste de nettoyage. Si vous
       rencontrez un autre événement pour le descripteur 13 dans votre  traitement,  vous  verrez
       qu'il a été supprimé précédemment sans que cela ne prête à confusion.

VERSIONS

       L'API  epoll  a été introduite dans le noyau Linux 2.5.44. Sa prise en charge par la glibc
       est ajoutée dans la version 2.3.2.

CONFORMITÉ

       L'API epoll est spécifique à Linux. Certains autres systèmes  fournissent  des  mécanismes
       similaires. Par exemple, FreeBSD propose kqueue et Solaris /dev/poll.

NOTES

       L’ensemble  des  descripteurs de fichier qui sont supervisés par un descripteur de fichier
       d’epoll peut être visualisé à l’aide de l’entrée pour le descripteur  de  fichier  d’epoll
       dans  le  répertoire  /proc/[pid]/fdinfo  du  processus.  Consultez  proc(5)  pour plus de
       détails.

       L’opération KCMP_EPOLL_TFD de kcmp(2) peut être utilisée pour tester si un descripteur  de
       fichier est présent dans une instance d’epoll.

VOIR AUSSI

       epoll_create(2), epoll_create1(2), epoll_ctl(2), epoll_wait(2), poll(2), select(2)

COLOPHON

       Cette  page  fait partie de la publication 5.10 du projet man-pages Linux. Une description
       du projet et des instructions pour signaler des anomalies et la dernière version de  cette
       page peuvent être trouvées à l'adresse https://www.kernel.org/doc/man-pages/.

TRADUCTION

       La  traduction  française  de  cette  page  de  manuel  a  été créée par Christophe Blaess
       <https://www.blaess.fr/christophe/>, Stéphan  Rafin  <stephan.rafin@laposte.net>,  Thierry
       Vignaud  <tvignaud@mandriva.com>,  François Micaux, Alain Portal <aportal@univ-montp2.fr>,
       Jean-Philippe   Guérard   <fevrier@tigreraye.org>,   Jean-Luc   Coulon   (f5ibh)    <jean-
       luc.coulon@wanadoo.fr>,    Julien    Cristau    <jcristau@debian.org>,    Thomas   Huriaux
       <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin
       Duneau  <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis
       Barbier <barbier@debian.org>, David Prévot <david@tilapin.org>  et  Jean-Paul  Guillonneau
       <guillonneau.jeanpaul@free.fr>

       Cette  traduction  est  une  documentation libre ; veuillez vous reporter à la GNU General
       Public  License  version 3  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩   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 à debian-l10n-french@lists.debian.org ⟨⟩.