select(2) System Calls Manual select(2) NOM select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO, fd_set - Multiplexage d'entrees-sorties synchrones BIBLIOTHEQUE Bibliotheque C standard (libc, -lc) SYNOPSIS #include typedef /* ... */ fd_set; int select(int nfds, fd_set *_Nullable restrict readfds, fd_set *_Nullable restrict writefds, fd_set *_Nullable restrict exceptfds, struct timeval *_Nullable restrict timeout); void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set); int pselect(int nfds, fd_set *_Nullable restrict readfds, fd_set *_Nullable restrict writefds, fd_set *_Nullable restrict exceptfds, const struct timespec *_Nullable restrict timeout, const sigset_t *_Nullable restrict sigmask); Exigences de macros de test de fonctionnalites pour la glibc (consulter feature_test_macros(7)) : pselect() : _POSIX_C_SOURCE >= 200112L DESCRIPTION Attention : select() ne peut surveiller que des descripteurs de fichier dont le numero est inferieur a FD_SETSIZE (1024) -- une limite excessivement basse pour beaucoup d'applications modernes -- et cette limite ne changera pas. Toutes les applications modernes devraient utiliser a la place poll(2) ou epoll(7) qui ne souffrent pas de cette limitation. select() permet a un programme de surveiller plusieurs descripteurs de fichier, en attendant qu'au moins l'un de ces descripteurs soit << pret >> pour une certaine classe d'operations d'entree-sortie (par exemple une entree est possible). Un descripteur de fichier est considere comme pret s'il est possible d'effectuer l'operation correspondante (par exemple read(2) ou un write(2) assez petit) sans bloquer. fd_set Un type de structure qui peut representer un ensemble de descripteurs de fichier. Selon POSIX, le nombre maximal de descripteurs de fichier dans une structure fd_set est la valeur de la macro FD_SETSIZE. Ensembles de descripteurs de fichier Les parametres principaux de select() sont trois << ensembles >> de descripteurs de fichier (declares avec le type fd_set), qui permettent a l'appelant d'attendre trois classes d'evenements sur l'ensemble de descripteurs de fichier indique. Chacun des parametres de fd_set peut etre indique comme NULL si aucun descripteur de fichier ne doit etre surveille pour la classe d'evenements correspondante. Important : lors de la sortie, chacun des ensembles de descripteurs de fichier est modifie sur place pour indiquer quels descripteurs de fichier sont actuellement << prets >>. Par consequent, si on utilise select() dans une boucle, les ensembles doivent etre reinitialises avant chaque appel. Le contenu d'un ensemble de descripteurs de fichier peut etre manipule en utilisant les macros suivantes : FD_ZERO() Cette macro efface (supprime tous les descripteurs de fichier) set. Elle doit etre utilisee en tant que premiere etape de l'initialisation d'un ensemble de descripteurs de fichier. FD_SET() Cette macro ajoute le descripteur de fichier fd a set. L'ajout d'un descripteur de fichier deja present dans l'ensemble est sans effet et ne produit pas d'erreur. FD_CLR() Cette macro supprime le descripteur de fichier fd de set. La suppression d'un descripteur de fichier non present dans l'ensemble est sans effet et ne produit pas d'erreur. FD_ISSET() select() modifie le contenu des ensembles en fonction des regles decrites ci-dessous. Apres un appel a select(), la macro FD_ISSET() peut etre utilisee pour tester si un descripteur de fichier est present dans un ensemble. FD_ISSET() ne renvoie pas zero si le descripteur de fichier fd est present dans set, sinon il le renvoie. Arguments Les parametres de select() sont les suivants : readfds Les descripteurs de fichier de cet ensemble sont surveilles pour voir s'ils sont prets en lecture. Un descripteur de fichier est pret si une operation de lecture ne bloquera pas ; en particulier, le descripteur de fichier est pret sur une fin-de-fichier. Apres que select() ait renvoye, readfds sera vide de tous les descripteurs de fichier sauf ceux prets en lecture. writefds Les descripteurs de fichier de cet ensemble sont surveilles pour voir s'ils sont prets en ecriture. Un descripteur de fichier est pret si une operation d'ecriture ne bloquera pas. Cependant, meme si un descripteur de fichier est indique comme inscriptible, une ecriture abondante peut toujours bloquer. Apres que select() ait renvoye, writefds() sera vide de tous les descripteurs de fichier, sauf ceux prets en ecriture. exceptfds Les descripteurs de fichier de cet ensemble sont surveilles en cas de << conditions exceptionnelles >>. Pour des exemples de conditions exceptionnelles, voir le point sur POLLPRI dans poll(2). Apres que select() ait renvoye, exceptfds() sera vide de tous les descripteurs de fichier, sauf ceux ou s'est produite une condition exceptionnelle. nfds Ce parametre doit etre positionne sur le numero du plus grand descripteur des trois ensembles, plus 1. Les descripteurs de fichier indiques dans chaque ensemble sont verifies dans cette limite (mais voir BOGUES). timeout L'argument timeout est une structure timeval (decrite ci-dessous) qui precise la duree de l'intervalle pendant lequel select() restera bloque dans l'attente d'un descripteur de fichier disponible. L'appel restera bloque jusqu'a : - un descripteur de fichier devient pret ; - l'appel est interrompu par un gestionnaire de signal ; - le delai expire. Notez que l'intervalle timeout est arrondi selon la granularite de l'horloge du systeme, et un retard d'ordonnancement du noyau peut entrainer un leger depassement de la duree de blocage. Si les deux champs de la structure timeval valent zero, select() renvoie immediatement (c'est utile pour la scrutation). Si timeout est indique comme etant NULL, select() restera bloque dans l'attente d'un descripteur de fichier disponible : pselect() L'appel systeme pselect() permet a une application d'attendre de maniere securisee un signal ou qu'un descripteur de fichier soit pret. select() et pselect() ont un comportement identique, avec trois differences : - La fonction select() utilise un delai exprime avec une struct timeval (en secondes et microsecondes), alors que pselect() utilise une struct timespec (en secondes et nanosecondes). - La fonction select() peut modifier le parametre timeout pour indiquer le temps restant. La fonction pselect() ne change pas ce parametre. - La fonction select() n'a pas de parametre sigmask et se comporte comme pselect() avec une valeur NULL pour sigmask sigmask est un pointeur sur un masque de signaux (consultez sigprocmask(2)). S'il n'est pas NULL, alors pselect() remplace d'abord le masque de signaux en cours par celui indique dans sigmask, puis invoque la fonction << select >>, et enfin restaure le masque de signaux a nouveau (si sigmask est NULL, le masque de signaux n'est pas modifie pendant l'appel pselect()). Mise a part la difference de precision de l'argument timeout, l'appel pselect() suivant : ready = pselect(nfds, &readfds, &writefds, &exceptfds, timeout, &sigmask); est equivalent a executer de facon atomique les appels suivants : sigset_t origmask; pthread_sigmask(SIG_SETMASK, &sigmask, &origmask); ready = select(nfds, &readfds, &writefds, &exceptfds, timeout); pthread_sigmask(SIG_SETMASK, &origmask, NULL); La raison de la presence de pselect() est que pour l'attente d'un evenement, que ce soit un signal ou une condition sur un descripteur, un test atomique est necessaire pour eviter les situations de concurrence. (Supposons que le gestionnaire de signaux active un drapeau global et renvoie. Alors un test de ce drapeau, suivi d'un appel select() peut bloquer indefiniment si le signal arrive juste apres le test mais avant l'appel. A l'inverse, pselect() permet de bloquer les signaux d'abord, traiter les signaux deja recus, puis invoquer pselect() avec le sigmask desire, en evitant la situation de concurrence.) Delai Le parametre timeout de select() est une structure du type suivant : struct timeval { time_t tv_sec; /* secondes */ suseconds_t tv_usec; /* microsecondes */ }; Le parametre correspondant a pselect() est une structure timespec(3). Sous Linux, la fonction select() modifie timeout pour indiquer le temps non endormi ; la plupart des autres implementations ne le font pas (POSIX.1 autorise les deux comportements). Cela pose des problemes a la fois pour porter sur d'autres systemes du code developpe sous Linux qui utilise cette valeur de timeout modifiee, et pour porter sous Linux du code qui reutilise plusieurs fois la struct timeval pour plusieurs select()s dans une boucle sans la reinitialiser. La meilleure attitude a adopter est de considerer timeout comme indefini apres le retour de select(). VALEUR RENVOYEE En cas de reussite select() et pselect() renvoient le nombre de descripteurs dans les trois ensembles de descripteurs renvoyes (c'est-a-dire le nombre total de bits definis dans readfds, writefds et exceptfds) qui peut etre nul si le delai d'expiration a ete atteint avant qu'un descripteur de fichier ne soit pret. En cas d'erreur, la valeur de retour est -1 et errno est definie pour preciser l'erreur ; les ensembles de descripteurs de fichiers ne sont pas modifies et timeout devient indefini. ERREURS EBADF Un descripteur de fichier non valable etait dans l'un des ensembles (peut-etre un descripteur deja ferme ou sur lequel une erreur s'est produite).Cependant, consultez BOGUES EINTR Un signal a ete intercepte ; consultez signal(7). EINVAL nfds est negatif ou depasse la limite de ressource RLIMIT_NOFILE (voir getrlimit(2)). EINVAL La valeur contenue dans timeout n'est pas valable. ENOMEM Incapacite d'allouer de la memoire pour des tables internes. VERSIONS Sur d'autres systemes UNIX, select() peut echouer avec l'erreur EAGAIN si le systeme ne parvient pas a allouer des ressources internes du noyau contrairement a l'erreur ENOMEM de Linux. POSIX specifie cette erreur pour poll(2) mais pas pour select(2). Des programmes portables peuvent souhaiter verifier EAGAIN et la boucle comme avec EINTR. STANDARDS POSIX.1-2008. HISTORIQUE select() POSIX.1-2001, 4.4BSD (apparu dans 4.2BSD). Generalement portable depuis ou vers des systemes non BSD gerant des clones de la couche sockets BSD (y compris les variantes de System V). Sachez neanmoins, que les variantes de System V definissent la variable timeout avant le retour alors que les variantes BSD ne le font pas. pselect() Linux 2.6.16. POSIX.1g, POSIX.1-2001. Precedemment, il etait emule dans la glibc (mais voir la section BOGUES). fd_set POSIX.1-2001. NOTES L'en-tete suivant fournit aussi le type fd_set : . Un ensemble fd_set est un tampon de taille fixe. Executer FD_CLR() ou FD_SET() avec fd negatif ou superieur ou egal a FD_SETSIZE resultera en un comportement indefini. Plus encore, POSIX demande que fd soit un descripteur de fichier valable. Les operations select() et pselect() ne sont pas concernees par l'attribut O_NONBLOCK. L'astuce du << self-pipe >> Sur les systemes sans pselect, une gestion plus sure (et plus portable) des signaux peut etre obtenue en utilisant l'astuce du << self-pipe >> : un gestionnaire de signal ecrit un octet dans un tube dont select() dans le programme principal surveille l'autre extremite. (Pour eviter la possibilite de blocage lors de l'ecriture dans un tube pouvant etre plein ou de la lecture dans un tube pouvant etre vide, des entrees et sorties non bloquantes sont utilisees pour la lecture et l'ecriture dans le tube.) Emuler usleep(3) Avant l'arrivee de usleep(3), certaines applications appelaient select() avec trois ensembles de descripteurs vides, nfds nul et un delai timeout non NULL, afin d'endormir, de maniere portable, le processus avec une precision plus fine que la seconde. Correspondance entre les notifications de select() et de poll() Dans les sources du noyau Linux, nous trouvons les definitions suivantes qui montrent la correspondance entre les notifications de lisibilite, d'inscriptibilite et de condition exceptionnelle de select() et les notifications d'evenements fournies par poll(2) et epoll(7) : #define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR) /* Pret en lecture */ #define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR) /* Pret en ecriture */ #define POLLEX_SET (EPOLLPRI) /* Condition exceptionnelle */ Programmes multithreades Si un descripteur de fichier surveille par select() est ferme dans un autre thread, le resultat est indetermine. Sur certains systemes UNIX, select() debloque et termine, avec une indication que le descripteur de fichier est pret (une operation entree/sortie ulterieure risque d'echouer avec une erreur, sauf si le descripteur de fichier a ete reouvert entre le moment ou select() termine et l'execution des operations entree/sortie). Sur Linux (et d'autres systemes), la fermeture du descripteur de fichier dans un autre thread n'a aucun effet sur select(). En resume, toute application qui s'appuie sur un comportement particulier dans ce scenario doit etre consideree comme boguee. Differences entre bibliotheque C et noyau Le noyau Linux autorise les ensembles de descripteurs de fichier de n'importe quelle taille, en determinant la taille des ensembles a verifier a partir de la valeur de nfds. Cependant, dans l'implementation de la glibc, le type fd_set a une taille fixe. Voir aussi les BOGUES. L'interface pselect() decrite dans cette page est implementee par la glibc. L'appel systeme Linux sous-jacent est appele pselect6(). Cet appel systeme a un comportement quelque peu different de la fonction d'enveloppe de la glibc. L'appel systeme pselect6() de Linux modifie son argument timeout. Cependant, la fonction d'enveloppe de la glibc cache ce comportement en utilisant une variable locale pour l'argument timeout qui est passe a l'appel systeme. Par consequent, la fonction pselect() de la glibc ne modifie pas son parametre timeout, ce qui est le comportement prescrit par POSIX.1-2001. Le dernier argument de l'appel systeme pselect6() n'est pas un pointeur sigset_t *, mais une structure de la forme suivante : struct { const kernel_sigset_t *ss; /* Pointeur vers un ensemble de signaux */ size_t ss_len; /* Taille (en octets) de l'objet vers lequel pointe 'ss' */ }; Cela permet a l'appel systeme d'obtenir a la fois le pointeur vers l'ensemble de signaux et sa taille, tout en permettant a la plupart des architectures de ne prendre en charge qu'un maximum de 6 arguments pour un appel systeme. Voir sigprocmask(2) pour un point sur la difference entre la vision du noyau et celle de la libc de l'ensemble de signaux. Details historiques sur la glibc La glibc 2.0 fournissait une mauvaise version de pselect() qui n'avait pas d'argument sigmask. De la glibc 2.1 a la glibc 2.2.1, on peut definir _GNU_SOURCE afin d'obtenir la declaration de pselect() depuis . BOGUES POSIX autorise une implementation a definir une limite superieure indiquee a l'aide de la constante FD_SETSIZE, dans l'intervalle de descripteurs de fichier qui peuvent etre indiques dans un ensemble de descripteurs de fichier. Le noyau Linux n'impose pas de limite fixe mais l'implementation de la glibc fait que fd_set est un type de taille fixe, ou FD_SETSIZE est defini a 1024 et ou les macros FD_*() agissent en fonction de cette limite. Pour surveiller des descripteurs de fichier superieurs a 1023, utilisez plutot poll(2) ou epoll(7). L'implementation des parametres de fd_set en tant qu'arguments valeur-resultat est une erreur de conception qui est evitee dans poll(2) et epoll(7). Selon POSIX, select() devrait verifier tous les descripteurs de fichier des trois ensembles jusqu'a nfds-1. Cependant, l'implementation actuelle ignore tout descripteur de fichier dans ces ensembles superieur au numero le plus eleve de descripteur de fichier que le processus a ouvert. Selon POSIX, un tel descripteur de fichier indique dans l'un des ensembles devrait provoquer une erreur EBADF. A partir de la glibc 2.1, la glibc fournissait une emulation de pselect() implementee avec sigprocmask(2) et select(). Cette implementation etait vulnerable a la condition de concurrence que pselect() etait concu pour eviter. Les versions recentes de la glibc utilisent l'appel systeme pselect() (sans risque de concurrence) si le noyau le fournit. Sous Linux, select() peut signaler un descripteur de fichier socket comme << pret a lire >> alors qu'une lecture suivante bloque. Cela peut, par exemple, survenir lorsque des donnees sont arrivees mais, apres verification, ont une mauvaise somme de controle et sont rejetees. Cela peut egalement arriver dans d'autres circonstances dans lesquelles le descripteur de fichier est faussement signale comme pret. Aussi, il est plus sur d'utiliser O_NONBLOCK sur des sockets qui ne devraient pas bloquer. Sous Linux, select() modifie egalement timeout si l'appel est interrompu par un gestionnaire de signaux (code d'erreur EINTR). Cela est interdit par POSIX.1. L'appel systeme pselect() de Linux se comporte de la meme facon, mais la glibc cache cette particularite en copiant timeout vers une variable locale et en passant cette variable a l'appel systeme. EXEMPLES #include #include #include int main(void) { int retval; fd_set rfds; struct timeval tv; /* Surveiller stdin (fd 0) en attente d'entrees. */ FD_ZERO(&rfds); FD_SET(0, &rfds); /* Attendre jusqu'a 5 secondes. */ tv.tv_sec = 5; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv); /* Ne pas s'appuyer sur la valeur de tv maintenant ! */ if (retval == -1) perror("select()"); else if (retval) printf("Des donnees sont disponibles maintenant\n"); /* FD_ISSET(0, &rfds) est alors vrai. */ else printf("Aucune donnee durant les cinq secondes.\n"); exit(EXIT_SUCCESS); } VOIR AUSSI accept(2), connect(2), poll(2), read(2), recv(2), restart_syscall(2), send(2), sigprocmask(2), write(2), timespec(3), epoll(7), time(7) Pour un tutoriel avec des exemples, consultez select_tut(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 , Cedric Boutillier , Frederic Hantrais , Jean-Philippe MENGUAL et Jean-Pierre Giraud 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 select(2)