Loading

NOM

       epoll - Notifications d’événements d’entrées-sorties.

SYNOPSIS

       #include <sys/epoll.h>

       epoll  est  une variante de poll(2) que l’on peut déclencher par niveau
       ou par changement d’état, et monte bien en charge pour un grand  nombre
       de  descripteurs  simultanés.  Les appels système suivants sont fournis
       pour créer et superviser une instance epoll :

       *  Une  instance  epoll  créée  par  epoll_create(2),  qui  renvoie  un
          descripteur de fichier référençant l’instance epoll (la version plus
          récente    epoll_create1(2)    étend    les    fonctionnalités    de
          epoll_create(2)).

       *  L’intérêt pour un descripteur de fichier est ensuite enregistré avec
          epoll_ctl(2). L’ensemble de descripteurs  de  fichiers  actuellement
          enregistré  pour  une  instance epoll est parfois appelé un ensemble
          epoll.

       *  Enfin, l’attente est effectivement démarrée avec epoll_wait(2).

   Détection de niveau et détection de transition
       L’interface de distribution d’événements de epoll  est  capable  de  se
       comporter en détection de niveau (Level Triggered - LT) ou en détection
       de transition (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 epoll.

       2. Celui qui écrit dans le tube envoie 2 Ko de données.

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

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

       5. Un appel de epoll_wait(2) est effectué.

       Si le descripteur rfd a été ajouté  à  l’ensemble  epoll  en  utilisant
       l’attribut  EPOLLET  (edge-triggered), 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  les  tampons  d’entrée du fichier et 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 Edge Triggered délivre les  événements  seulement  lorsque
       des  événements  surviennent sur le 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 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 ne bloque, par une famine, une tâche qui
       gère  plusieurs  descripteurs  de  fichier.  L’utilisation   préconisée
       d’epoll  avec  l’interface en détection de changements (EPOLLET) est la
       suivante :

              i   avec des descripteurs non bloquants ; et

              ii  en attendant seulement après qu’un read(2) ou un write(2)  a
                  renvoyé EAGAIN.

       Au  contraire,  lorsqu’il  est utilisé avec l’interface en détection 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.

       Même dans un epoll de type Edge Triggered, 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.

   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)
              Ceci  définit  une  limite  au  nombre  total de descripteurs de
              fichiers qu’un utilisateur peut enregistrer  au  travers  toutes
              les  instances  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 dutilisation
       Tandis que l’utilisation de epoll  avec  un  déclenchement  par  niveau
       correspond  à  la  même  sémantique  que  poll(2), le déclenchement par
       changement d’état nécessite plus d’explication pour éviter les  cas  de
       blocage.  Dans cet exemple, le lecteur emploie une socket non bloquante
       sur laquelle listen(2)  a  été  appelée.  La  fonction  do_use_fd()  va
       utiliser  le nouveau descripteur de fichier, jusqu’à ce que EAGAIN soit
       renvoyé par read(2) ou par write(2). Une application  fonctionnant  par
       transition d’état devrait, après réception d’EAGAIN, enregistrer l’état
       en cours, afin que l’appel suivant  de  do_use_fd()  continue  avec  le
       read(2) ou le write(2) où il s’est arrêté.

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

           /* Set up listening socket, 'listen_sock' (socket(),
              bind(), listen()) */

           epollfd = epoll_create(10);
           if (epollfd == -1) {
               perror("epoll_create");
               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_pwait");
                   exit(EXIT_FAILURE);
               }

               for (n = 0; n < nfds; ++n) {
                   if (events[n].data.fd == listen_sock) {
                       conn_sock = accept(listen_sock,
                                       (struct sockaddr *) &local, &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   epoll  (EPOLL_CTL_ADD)  une  fois,  en  spécifiant
       (EPOLLIN|EPOLLOUT). Ceci évite de basculer sans cesse entre EPOLLIN  et
       EPOLLOUT lors des appels epoll_ctl(2) avec EPOLL_CTL_MOD.

   Questions/Réponses
       Q0  Quelle  est  la  clé  utilisée  pour distinguer les descripteurs de
           fichier enregistrés dans un ensemble epoll ?

       A0  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).

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

       A1  Vous aurez  probablement  un  EEXIST.  Cependant  il  est  possible
           d’ajouter  un  duplicat  de  descripteur (dup(2), dup2(2), fcntl(2)
           F_DUPFD) sur la même instance epoll. Ceci peut être  une  technique
           utile  pour le filtrage d’événements, si les descripteurs duplicats
           sont enregistré avec un masque d’événements events différent.

       Q2  Deux instances 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 epoll en même temps ?

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

       Q3  Peut-on  utiliser   le   descripteur   de   epoll   lui-même   avec
           poll/epoll/select?

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

       Q4  Que se passe-t-il si on cherche à placer un  descripteur  de  epoll
           dans son propre ensemble ?

       A4  L’appel  à  epoll_ctl(2)  échouera  (EINVAL). Toutefois vous pouvez
           ajouter un descripteur de epoll dans un autre ensemble epoll.

       Q5  Puis-je envoyer le descripteur de epoll à travers une  socket  Unix
           vers un autre processus ?

       A5  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
           l’ensemble epoll.

       Q6  Est-ce    que   la   fermeture   d’un   descripteur   le   supprime
           automatiquement de tous les ensembles epoll ?

       A6  Oui, mais prenez note des points qui  suivent.  Un  descripteur  de
           fichier  est  une référence vers la description d’un fichier ouvert
           (voir open(2)). À chaque fois qu’un descripteur est  dupliqué  avec
           dup(2),   dup2(2),   fcntl(2)   F_DUPFD   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 à exister jusqu’à
           ce que tous les descripteurs de fichier  qui  s’y  réfèrent  soient
           fermés.  Un  descripteur  de fichier est retiré d’un ensemble epoll
           seulement après  que  tous  les  descripteurs  de  fichier  qui  se
           réfèrent  à  la  description  de fichier ouvert sous-jacente soient
           fermés (ou avant si le  descripteur  est  explicitement  retiré  en
           utilisant  epoll_ctl() EPOLL_CTL_DEL). Ceci signifie que même après
           qu’un descripteur de fichier d’un ensemble epoll  soit  fermé,  des
           événements  peuvent  toujours  être remontés pour ce descripteur de
           fichier si d’autres descripteur de fichier, se référant à  la  même
           description de fichier sous-jacente, restent ouvert.

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

       A7  Ils sont combinés.

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

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

       Q9  Dois-je  lire/écrire  sans  cesse  un  descripteur  jusqu’à obtenir
           EAGAIN avec l’attribut EPOLLET (comportement edge-triggered) ?

       A9  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. Vous devez le
           considérer 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, une socket
           datagramme  ou  un  terminal  en mode canonique), la seule façon de
           détecter la fin de l’espace d’entrée-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-sorties
           peut-être vérifiée par la quantité de données lues ou écrites  avec
           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ûrs  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  garantir  que  le  descripteur  de  fichier   surveillé
           correspond toujours à un fichier de type flux)

   Erreurs possibles et moyens de les éviter
       o Famine (edge-triggered)

       S’il  y  a  un  gros  volume  d’entrées-sorties,  il est possible qu’en
       essayant de les traiter,  d’autres  fichiers  ne  soient  pas  pris  en
       compte,  ce  qu’on  appelle  un  cas  de  famine. Ce problème n’est pas
       spécifique à epoll.

       La solution est de maintenir une liste de descripteurs prêts et de  les
       marquer   comme   tels  dans  leur  structure  associée,  permettant  à
       l’application de savoir quels fichiers traiter, en  organisant  l’ordre
       au mieux. Ceci permet aussi d’ignorer les événements ultérieurs sur des
       descripteurs prêts.

       o Utilisation dun cache dévénements...

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

       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),  et  marquer  sa structure associée comme supprimée. 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.  La  prise  en
       charge par la glibc a été 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.

VOIR AUSSI

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

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  mise  à  jour  par  Christophe
       Blaess  <http://www.blaess.fr/christophe/> entre 1996 et 2003, puis par
       Alain Portal <aportal AT univ-montp2 DOT fr> jusqu’en 2006, et  mise  à
       disposition sur http://manpagesfr.free.fr/.

       Les mises à jour et corrections de la version présente dans Debian sont
       directement gérées par Julien Cristau <jcristau@debian.org> 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> ».