epoll(7) Miscellaneous Information Manual epoll(7) NOM epoll - Notifications d'evenements d'entrees et sorties SYNOPSIS #include DESCRIPTION L'interface de programmation (API) epoll realise une tache similaire a poll(2) : surveiller plusieurs descripteurs de fichier pour voir si des E/S y sont possibles. L'API epoll peut etre declenchee par changement de niveau ou par changement d'etat et s'adapte bien a un grand nombre de descripteurs surveilles. 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 etre consideree comme un conteneur pour deux listes : - La liste interest (parfois appelee l'ensemble epoll) : l'ensemble des descripteurs de fichier que le processus a enregistres comme interessants a surveiller. - La liste ready : l'ensemble des descripteurs de fichier prets (ready) pour des E/S. Cette liste est un sous-ensemble de (plus precisement, un ensemble de references de) descripteurs de fichier de la liste interest. La liste ready est alimentee dynamiquement par le noyau selon le resultat des activites d'E/S de ces descripteurs de fichier. Les appels systeme suivants sont fournis pour creer et gerer une instance d'epoll : - epoll_create(2) cree une instance d'epoll et renvoie un descripteur de fichier referencant cette instance. La version plus recente d'epoll_create1(2) etend les fonctionnalites d'epoll_create(2). - L'interet pour des descripteurs de fichier particuliers est ensuite enregistre avec epoll_ctl(2), qui ajoute les articles dans la liste interest de l'instance d'epoll. - epoll_wait(2) attend les evenements d'E/S, en bloquant le thread appelant si aucun evenement n'est actuellement disponible. Cet appel systeme peut etre considere comme recherchant des articles dans la liste ready de l'instance d'epoll. Detection par changement de niveau ou d'etat L'interface de distribution d'evenements d'epoll est capable de se comporter en detection de changement de niveau (Level Triggered -- LT) ou d'etat (Edge Triggered -- ET). La difference entre ces deux mecanismes est decrite ci-dessous. Supposons que le scenario suivant se produise : (1) Le descripteur de fichier qui represente le cote lecture d'un tube (rfd) est enregistre dans l'instance d'epoll. (2) Une ecriture dans le tube envoie 2 Ko de donnees du cote ecriture du tube. (3) Un appel a epoll_wait(2) est effectue et renvoie rfd comme descripteur de fichier pret. (4) Un lecteur du tube lit 1 Ko de donnees depuis rfd. (5) Un appel d'epoll_wait(2) est effectue. Si le descripteur rfd a ete ajoute a l'ensemble epoll en utilisant l'attribut EPOLLET (detection de changement d'etat), l'appel epoll_wait(2), realise a l'etape 5, va probablement bloquer bien qu'il y ait des donnees toujours presentes dans le tampon d'entree du fichier tandis que le pair distant attendra une reponse basee sur les donnees qu'il a deja envoyees. La raison en est que le mecanisme de distribution d'evenements detectes par changement d'etat delivre les evenements seulement lorsque des evenements surviennent dans le descripteur de fichier supervise. Ainsi, a l'etape 5, l'appelant peut attendre des donnees qui sont deja presentes dans le tampon d'entree. Dans l'exemple ci-dessus, un evenement sur rfd sera declenche a cause de l'ecriture a l'etape 2 et l'evenement est consomme dans l'etape 3. Comme l'operation de lecture de l'etape 4 ne consomme pas toutes les donnees du tampon, l'appel a epoll_wait(2) effectue a l'etape 5 peut verrouiller indefiniment. Une application qui emploie l'attribut EPOLLET de la fonction epoll devrait toujours utiliser des descripteurs non bloquants pour eviter qu'une lecture ou une ecriture affame une tache qui gere plusieurs descripteurs de fichier. L'utilisation preconisee d'epoll comme interface en detection par changement d'etat (EPOLLET) est la suivante : (1) avec des descripteurs non bloquants ; (2) en attente d'evenement seulement apres qu'un read(2) ou un write(2) ait renvoye EAGAIN. En revanche, lorsqu'il est utilise avec l'interface en detection par changement de niveau (par defaut si EPOLLET n'est pas specifie), epoll est une alternative plus rapide a poll(2) et peut etre employe a chaque fois que ce dernier est utilise, car il utilise la meme semantique. Puisque meme dans un epoll de type detection le changement d'etat, plusieurs evenements peuvent etre generes a la reception de nombreux blocs de donnees, l'appelant peut, en specifiant l'attribut EPOLLONESHOT, faire desactiver par epoll le descripteur de fichier associe apres la reception d'un evenement avec epoll_wait(2). Lorsque l'attribut EPOLLONESHOT est specifie, il est de la responsabilite de l'appelant de rearmer le descripteur en utilisant epoll_ctl(2) avec EPOLL_CTL_MOD. Si plusieurs threads (ou processus si les processus enfant ont herite du descripteur de fichier d'epoll a travers fork(2)) sont bloques dans epoll_wait(2) en attente du meme descripteur de fichier d'epoll et qu'un descripteur de fichier dans la liste interest, qui est marque pour une notification par detection de changement d'etat (EPOLLET), devienne pret, seul un des threads (ou processus) est reveille de epoll_wait(2). Cela fournit une optimisation utile pour eviter la bousculade de reveils (thundering herd) dans certain scenarios. Interaction avec autosleep Si le systeme est en mode autosleep a l'aide de /sys/power/autosleep et qu'un evenement survient et sort le peripherique de sa veille, le pilote de peripherique ne gardera le peripherique actif que jusqu'a la mise en file d'attente de l'evenement. Pour garder le peripherique actif jusqu'au traitement de l'evenement, l'attribut EPOLLWAKEUP d'epoll_ctl(2) doit etre utilise. Quand l'attribut EPOLLWAKEUP est defini dans le champ events pour une struct epoll_event, le systeme sera garde actif a partir du moment ou l'evenement est mis en file d'attente, a l'aide de l'appel epoll_wait(2) qui renvoie l'evenement jusqu'a l'appel epoll_wait(2) suivant. Si l'evenement doit garder le systeme actif au dela de ce moment, alors un wake_lock separe devrait etre pris avant le second appel a epoll_wait(2). /proc interfaces Les interfaces suivantes peuvent etre utilisees pour limiter la quantite de memoire du noyau utilisee par epoll : /proc/sys/fs/epoll/max_user_watches (depuis Linux 2.6.28) Cela definit une limite au nombre total de descripteurs de fichiers qu'un utilisateur peut enregistrer au travers de toutes les instances d'epoll du systeme. La limite est imposee par identifiant d'utilisateur reel. Chaque descripteur de fichier enregistre coute environ 90 octets sur un noyau 32 bits et environ 160 octets sur un noyau 64 bits. Actuellement la valeur par defaut pour max_user_watches est de 1/25 (4%) de la memoire basse disponible, divise par le cout d'allocation en octets. Exemple d'utilisation Tandis que l'utilisation d'epoll avec un declenchement par changement de niveau correspond a la meme semantique que poll(2), le declenchement par changement d'etat necessite plus de clarification pour eviter des decrochages dans la boucle d'evenements de l'application. Dans cet exemple, l'ecouteur emploie un socket non bloquant sur lequel listen(2) a ete appele. La fonction do_use_fd() va utiliser le nouveau descripteur de fichier jusqu'a ce qu'EAGAIN soit renvoye par read(2) ou par write(2). Une application d'automate fini pilote par les evenements devrait, apres reception d'EAGAIN, enregistrer l'etat en cours, afin que lors de l'appel suivant a do_use_fd(), elle continue avec le read(2) ou le write(2) la ou elle s'est arretee. #define MAX_EVENTS 10 struct epoll_event ev, events[MAX_EVENTS]; int listen_sock, conn_sock, nfds, epollfd; /* Code to set up listening socket, '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 detection de changement d'etats, pour des raisons de performances, il est possible d'ajouter le descripteur de fichier dans l'interface d'epoll (EPOLL_CTL_ADD) apres, en specifiant (EPOLLIN|EPOLLOUT). Cela evite de basculer sans cesse entre EPOLLIN et EPOLLOUT lors des appels epoll_ctl(2) avec EPOLL_CTL_MOD. Questions/Reponses - Quelle est la cle utilisee pour distinguer les descripteurs de fichier enregistres dans une liste interest ? La cle est une combinaison du numero du descripteur de fichier et de la description du fichier ouvert (aussi connue comme << open file handle >>, la representation interne au noyau d'un fichier ouvert). - Que se passe-t-il si on enregistre deux fois le meme 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 meme instance d'epoll. Cela peut etre une technique utile pour le filtrage d'evenements, si les descripteurs dupliques sont enregistres avec des masques events differents. - Deux instances d'epoll peuvent-elles attendre le meme descripteur de fichier ? Si oui, les evenements seront-ils reportes sur les deux descripteurs de fichier d'epoll ? Oui, et les evenements seront rapportes aux deux. Toutefois, une programmation soignee est necessaire pour que cela soit fait correctement. - Est-ce que le descripteur d'epoll lui-meme est sujet a poll/epoll/select ? Oui. Si un descripteur de fichier d'epoll a des evenements en attente, alors il indiquera qu'il est lisible. - Que se passe-t-il si on cherche a placer un descripteur d'epoll dans son propre ensemble de descripteurs de fichier ? L'appel epoll_ctl(2) echouera (EINVAL). Toutefois vous pouvez ajouter un descripteur d'epoll dans un autre ensemble de descripteurs de fichier d'epoll. - Puis-je envoyer le descripteur d'epoll a travers un socket UNIX vers un autre processus ? Oui, mais il n'y a aucune raison de faire ca, puisque le processus recepteur n'aura pas de copie des descripteurs de fichier de la liste interest. - 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 reference vers la description d'un fichier ouvert (consultez open(2)). A chaque fois qu'un descripteur est duplique avec dup(2), dup2(2), F_DUPFD de fcntl(2) ou fork(2), un nouveau descripteur de fichier qui se refere au meme fichier ouvert est cree. Une description de fichier ouvert continue d'exister jusqu'a ce que tous les descripteurs de fichier qui s'y referent soient fermes. Un descripteur de fichier n'est retire d'une liste interest qu'apres la fermeture de tous les descripteurs de fichier qui se referent a la description de fichier ouvert sous-jacente. Cela signifie que meme apres la fermeture d'un descripteur de fichier faisant partie de cette liste, des evenements peuvent toujours etre rapportes pour ce descripteur de fichier si d'autres descripteurs de fichier, se referant a la meme description de fichier sous-jacente, restent ouverts. Pour empecher cela, le descripteur de fichier doit etre explicitement supprime de la liste (en utilisant epoll_ctl(2) EPOLL_CTL_DEL) avant qu'il ne soit duplique. Autrement, l'application doit assurer que tous les descripteurs soient fermes (ce qui peut etre difficile si les descripteurs ont ete dupliques en dehors du cadre par des fonctions de bibliotheque qui utilisent dup(2) ou fork(2)) - Si plus d'un evenement surviennent entre deux appels epoll_wait(2), sont-ils combines ou rapportes separement ? Ils sont combines. - Est-ce qu'une operation sur un descripteur affecte les evenements deja collectes mais pas encore rapportes ? Vous pouvez faire deux choses sur un descripteur existant. Une suppression serait sans effet dans ce cas. Une modification reverifie les entrees et sorties disponibles. - Dois-je lire/ecrire sans cesse un descripteur jusqu'a obtenir EAGAIN si l'attribut EPOLLET est utilise (comportement par detection de changement d'etat) ? La reception d'un evenement depuis epoll_wait(2) suggere qu'un descripteur est pret pour l'operation d'E/S desiree. Il doit etre considere comme pret jusqu'a ce que la prochaine lecture ou ecriture (non bloquante) remonte un EAGAIN. Quand et comment utiliser le descripteur depend de vous. Pour les fichiers orientes paquet ou jeton (par exemple, un socket datagramme ou un terminal en mode canonique), la seule facon de detecter la fin de l'espace d'entree et sortie pour les lectures ou ecritures est de continuer a lire ou ecrire jusqu'a la reception d'un EAGAIN. Pour les fichiers orientes flux (par exemple, les tubes, FIFO ou sockets en mode flux), la disponibilite des entrees et sorties peut aussi etre detectee en verifiant la quantite de donnees lues ou ecrites sur le descripteur. Par exemple, si vous appelez read(2) en demandant la lecture d'une certaine quantite de donnees et que read(2) en renvoie moins, vous pouvez etre sur d'avoir consomme tout le tampon d'entree pour le descripteur. La meme chose est vraie pour l'appel systeme write(2) (evitez cette derniere technique si vous ne pouvez pas garantir que le descripteur de fichier surveille corresponde toujours a un fichier de type flux). Erreurs possibles et moyens de les eviter - Starvation (edge-triggered) 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 probleme n'est pas specifique a epoll. La solution est de maintenir une liste de descripteurs prets et de marquer le descripteur de fichier pret dans leur structure associee, permettant a l'application de savoir quels fichiers traiter mais toujours en tourniquet englobant tous les fichiers prets. Cela permet aussi d'ignorer les evenements ulterieurs sur des descripteurs prets. - If using an event cache... Si vous utilisez un cache d'evenements, ou stockez tous les descripteurs renvoyes par epoll_wait(2), alors assurez-vous de disposer d'un moyen de marquer dynamiquement leurs fermetures (c'est-a-dire causees par un traitement d'evenement precedent). Supposons que vous recevez 100 evenements d'epoll_wait(2) et que l'evenement 47 implique de fermer l'evenement 13. Si vous supprimez la structure et utilisez close(2) pour le descripteur de fichier pour l'evenement 13, alors votre cache peut encore contenir des evenements pour ce descripteur, posant alors des problemes de confusion. Une solution est d'invoquer, pendant le traitement de l'evenement 47, epoll_ctl(EPOLL_CTL_DEL) pour supprimer le descripteur 13, le fermer avec close(2), puis marquer sa structure associee comme supprimee et la lier a une liste de nettoyage. Si vous rencontrez un autre evenement pour le descripteur 13 dans votre traitement, vous verrez qu'il a ete supprime precedemment sans que cela ne prete a confusion. VERSIONS Some other systems provide similar mechanisms; for example, FreeBSD has kqueue, and Solaris has /dev/poll. STANDARDS Linux. HISTORIQUE Linux 2.5.44. glibc 2.3.2. NOTES The set of file descriptors that is being monitored via an epoll file descriptor can be viewed via the entry for the epoll file descriptor in the process's /proc/pid/fdinfo directory. See proc(5) for further details. L'operation KCMP_EPOLL_TFD de kcmp(2) peut etre utilisee pour tester si un descripteur de fichier est present dans une instance d'epoll. VOIR AUSSI epoll_create(2), epoll_create1(2), epoll_ctl(2), epoll_wait(2), poll(2), select(2) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot et Jean-Paul Guillonneau Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 epoll(7)