SELECT

Section: Manuel du programmeur Linux (2)
Updated: 18 juillet 2003
Index


NOM
SYNOPSIS
DESCRIPTION
Délai maximal
VALEUR RENVOYÉE
ERREURS
NOTES
EXEMPLE
CONFORMITÉ
NOTES
VOIR AUSSI
TRADUCTION

NOM

select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - Multiplexage d'entrées/sorties synchrones.

SYNOPSIS

/* D'après Posix 1003.1-2001 */
#include <sys/select.h>
/* D'après les standards précédents */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int pselect(int
n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t * sigmask);
FD_CLR(int
fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

DESCRIPTION

Les fonctions select et pselect attendent des changements d'état sur plusieurs descripteurs de fichiers.
Elles ont un comportement identique, avec trois différences :
(i)
La fonction select utilise un délai exprimé avec une struct timeval (secondes et microsecondes), alors que pselect utilise une struct timespec (secondes et nanosecondes).
(ii)
La fonction select peut modifier le paramètre timeout pour indiquer le temps restant. La fonction pselect ne change pas ce paramètre.
(iii)
La fonction select n'a pas de paramètre sigmask et se comporte comme pselect avec une valeur NULL pour sigmask

Il y a trois ensembles indépendants de descripteurs surveillés simultanément. Ceux de l'ensemble readfds seront surveillés pour vérifier si des caractères deviennent disponibles en lecture. Plus précisément, on vérifie si un appel-système de lecture ne bloquera pas - en particulier un descripteur en fin-de-fichier sera considéré comme prêt. Les descripteurs de l'ensemble writefds seront surveillés pour vérifier si une écriture ne bloquera pas. Ceux de exceptfds seront surveillés pour l'occurrence de conditions exceptionnelles. En sortie, les ensembles sont modifiés pour indiquer les descripteurs qui ont changé de statut.
Quatre macros sont disponibles pour la manipulation des ensembles FD_ZERO efface un ensemble. FD_SET et FD_CLR ajoutent et suppriment un descripteur dans un ensemble. FD_ISSET vérifie si un descripteur est contenu dans un ensemble, principalement utile après le retour de select.
n est le numéro du plus grand descripteur des 3 ensembles, plus 1.
timeout est une limite supérieure au temps passé dans select avant son retour. Elle peut être nulle, ce qui conduit select à revenir immédiatement. (Ce qui sert pour des surveillance en polling). Si le timeout est NULL (aucun), select peut bloquer indéfiniment.
sigmask est un pointeur sur un masque de signaux (voir sigprocmask(2)). S'il n'est pas NULL, alors pselect remplace d'abord le masque de signaux en cours par celui indiqué dans sigmask, puis invoque la fonction `select', et enfin restaure le masque de signaux à nouveau.
L'idée derrière pselect est que pour l'attente d'un évènement, que ce soit un signal ou une condition sur un descripteur, un test atomique est nécessaire pour éviter les situations de concurrence. (Supposons que le gestionnaire de signaux active un drapeau global et revienne. Alors un test de ce drapeaux, suivi d'un appel select() peut bloquer indéfiniment si le signal arrive juste après le test mais avant l'appel. A l'inverse, pselect permet de bloquer le signal d'abord, traiter les signaux déjà reçus, puis invoquer pselect() avec le sigmask, désiré, en évitant la situation de blocage). Comme Linux n'a pas encore d'appel-système pselect(), la routine de la bibliothèque GlibC 2 contient encore le défaut.

Délai maximal

Les structures temporelles concernées sont définies dans <sys/time.h> comme ceci :
struct timeval {
    long    tv_sec;         /* secondes      */
    long    tv_usec;        /* microsecondes */
};

  et
 
struct timespec {
    long    tv_sec;         /* secondes     */
    long    tv_nsec;        /* nanosecondes */
};

(However, see below on the POSIX 1003.1-2001 versions.)
Certaines applications appellent select nul, et un délai timeout non nul, afin d'endormir, de manière portable, le processus avec une précision plus fine que la seconde.
Sous Linux, la fonction select modifie timeout pour indiquer le temps restant mais la plupart des autres implémentations ne le font pas. Ceci pose des problèmes à la fois pour porter sur d'autres systèmes du code développé sous Linux qui utilise cette valeur de timeout modifiée, et pour porter sous Linux du code qui réutilise plusieurs fois la structure timeval sans la réinitialiser. La meilleure attitude à adopter est de considérer timeout comme indéfini après le retour de select.

VALEUR RENVOYÉE

En cas de réussite select et pselect renvoient le nombre de descripteurs dans les ensembles, qui peut être nul si le délai de timeout a expiré avant que quoi que ce soit d'intéressant ne se produise. Ils retournent -1 s'ils échouent, auquel cas errno contient le code d'erreur.

ERREURS

EBADF
Un descripteur de fichier (dans l'un des ensembles) est invalide.
EINTR
Un signal a été intercepté.
EINVAL
n est négatif
ENOMEM
Pas assez de mémoire pour le noyau.

NOTES

avec les trois ensembles vides, n

EXEMPLE

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int
main(void)
{
    fd_set rfds;
    struct timeval tv;
    int retval;

    /* Surveiller stdin (fd 0) en attente d'entrées */
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    /* Pendant 5 secondes maxi */
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv);
    /* Considérer tv comme indéfini maintenant ! */

    if (retval)
        printf("Données disponibles maintenant\n");
        /* FD_ISSET(0, &rfds) est vrai */
    else
        printf("Pas de données depuis 5 secondes\n");

    return (0);
}

CONFORMITÉ

BSD 4.4 (la fonction select est apparue dans BSD 4.2). Généralement portable depuis ou vers des systèmes non-BSD supportant des clones de la couche sockets BSD (y compris les variantes du Système V). Néanmoins, sachez que les variantes du système V fixent une variable de timeout avant le retour alors que les variantes BSD ne le font pas.
La fonction pselect est définie dans IEEE Std 1003.1g-2000 (POSIX.1g) et pour partie dans POSIX 1003.1-2001. On la trouve dans GlibC 2.1 et ultérieure. Glibc2.0 a une fonction de ce nom, mais sans le paramètre sigmask.

NOTES

Un ensemble fd_set est un buffer de taille fixe. Exécuter FD_CLR ou FD_SET avec fd négatif ou supérieur ou égal à FD_SETSIZE résultera en un comportement indéfini. Plus encore, POSIX demande que fd soit un descripteur de fichier valide.
En ce qui concerne les types impliqués, la situation classique est que les deux champs de la structure timeval soient des "long" (comme ci-dessous), et que la structure soit définie dans <sys/time.h>. La situation avec POSIX 1003.1-2001 est
    
struct timeval { 
    time_t         tv_sec;     /* seconds */
    suseconds_t    tv_usec;    /* microseconds */
};  

avec la structure définie dans <sys/select.h> et les types de données time_t et suseconds_t définis dans <sys/types.h>.
Concernant les prototypes, on demande classiquement l'inclusion de <time.h> pour select. Avec POSIX 1003.1-2001, on préfère inclure <sys/select.h> pour select et pselect. Les bibliothèques libc4 et libc5 n'avaient pas d'en-tête <sys/select.h>, mais avec les GlibC 2.0 et suivantes le fichier existe. Pour la GlibC 2.0, le prototype de pselect est toujours erroné. Avec la GlibC 2.1-2.2.1 le prototype de pselect est fourni si la constante _GNU_SOURCE est définie avant l'inclusion. Avec GlibC 2.2.2-2.2.4, il faut que la constante _XOPEN_SOURCE soit définie avec une valeur supérieure ou égale à 600. Quoiqu'il en soit, depuis POSIX 1003.1-2001, le bon prototype devrait être défini par défaut.

VOIR AUSSI

Pour un tutoriel avec des exemples, voir select_tut(2).
D'autres pages ayant un vague rapport : accept(2), connect(2), poll(2), read(2), recv(2), send(2), sigprocmask(2), write(2)

TRADUCTION

Christophe Blaess, 1996-2003.