AIO(7) Miscellaneous Information Manual AIO(7) NOM aio - Vue d'ensemble des entrees-sorties (E/S) asynchrones POSIX DESCRIPTION L'interface d'E/S asynchrones (AIO pour << asynchronous I/O >>) POSIX permet aux applications de declencher une ou plusieurs operations d'E/S realisees de facon asynchrone (c'est-a-dire en arriere-plan). La fin d'une operation d'E/S peut etre notifiee a l'application de differentes facons au choix : distribution d'un signal, instanciation d'un thread ou absence de notification. L'interface AIO POSIX est composee des fonctions suivantes : aio_read(3) Placer en file d'attente une requete de lecture. C'est l'equivalent asynchrone de read(2). aio_write(3) Placer en file d'attente une requete d'ecriture. C'est l'equivalent asynchrone de write(2). aio_fsync(3) Placer en file d'attente une requete de synchronisation pour des operations d'E/S sur un descripteur de fichier. C'est l'equivalent asynchrone de fsync(2) et fdatasync(2). aio_error(3) Obtenir l'etat d'erreur d'une requete d'E/S placee en file d'attente. aio_return(3) Obtenir l'etat de retour d'une requete d'E/S terminee. aio_suspend(3) Suspendre l'appelant jusqu'a la fin d'une ou plusieurs requetes d'E/S d'un ensemble indique. aio_cancel(3) Essayer d'annuler des requetes d'E/S en cours sur un descripteur de fichier indique. lio_listio(3) Placer en file d'attente plusieurs requetes d'E/S a partir d'un seul appel de fonction. La structure aiocb (<< asynchronous I/O control block >>, ou bloc de controle d'E/S asynchrones) definit les parametres de controle d'une operation d'E/S. Un argument de ce type est utilise avec toutes les fonctions precedentes. Cette structure est de la forme suivante : #include struct aiocb { /* L'ordre de ces champs depend de l'implementation */ int aio_fildes; /* Descripteur de fichier */ off_t aio_offset; /* Position dans le fichier */ volatile void *aio_buf; /* Emplacement du tampon */ size_t aio_nbytes; /* Longueur de transfert */ int aio_reqprio; /* Priorite de requete */ struct sigevent aio_sigevent; /* Methode de notification */ int aio_lio_opcode; /* Operation a realiser ; lio_listio() seulement */ /* Divers champs internes a l'implementation ne sont pas montres */ }; /* Codes operatoires pour << aio_lio_opcode >> : */ enum { LIO_READ, LIO_WRITE, LIO_NOP }; Les membres de cette structure sont les suivants : aio_fildes Le descripteur du fichier sur lequel les operations d'E/S sont a realiser. aio_offset La position dans le fichier ou les operations d'E/S sont a realiser. aio_buf Le tampon utilise pour le transfert de donnees des operations de lecture ou d'ecriture. aio_nbytes La taille du tampon pointe par aio_buf. aio_reqprio Valeur a soustraire de la priorite temps-reel du thread de l'appelant pour determiner la priorite d'execution de cette requete d'E/S (consultez pthread_setschedparam(3)). La valeur indiquee doit etre entre 0 et la valeur renvoyee par sysconf(_SC_AIO_PRIO_DELTA_MAX). Ce champ est ignore lors des operations de synchronisation de fichier. aio_sigevent Structure indiquant comment l'appelant sera notifie de la fin d'une operation d'E/S asynchrone. Les valeurs de aio_sigevent.sigev_notify peuvent etre SIGEV_NONE, SIGEV_SIGNAL et SIGEV_THREAD. Consultez sigevent(3type) pour plus de precisions. aio_lio_opcode Le type d'operation a realiser, utilise seulement pour lio_listio(3). En plus des fonctions standard precedentes, la bibliotheque C du projet GNU fournit l'extension suivante a l'API AIO POSIX : aio_init(3) Configurer les parametres pour regler le comportement de l'implementation AIO POSIX de la glibc. ERREURS EINVAL Le champ aio_reqprio de la structure aiocb etait inferieur a 0 ou superieur a la limite renvoyee par l'appel sysconf(_SC_AIO_PRIO_DELTA_MAX). STANDARDS POSIX.1-2008. HISTORIQUE POSIX.1-2001. glibc 2.1. NOTES Il est conseille de mettre a zero le tampon de bloc de controle avant utilisation (consultez memset(3)). Le tampon de bloc de controle et le tampon pointe par aio_buf ne doivent pas etre modifies pendant l'execution d'une operation d'E/S. Ces tampons doivent rester valables jusqu'a la fin de l'operation d'E/S. Les operations de lecture ou d'ecriture asynchrones simultanees qui utilisent la meme structure aiocb produisent des resultats indefinis. L'actuelle implementation AIO POSIX de Linux est fournie en espace utilisateur par la glibc. De nombreuses limites existent, en particulier le maintien de plusieurs threads pour realiser des operations d'E/S est tres couteux et monte mal en charge. L'implementation d'E/S asynchrones basee sur l'etat de la machine est en travaux depuis un moment sur le noyau (consultez io_submit(2), io_setup(2), io_cancel(2), io_destroy(2), io_getevents(2)), mais cette implementation n'a pas encore atteint le niveau ou l'implementation AIO POSIX peut etre entierement reimplementee en utilisant les appels systeme du noyau. EXEMPLES Le programme suivant ouvre chaque fichier nomme en argument de sa ligne de commande et place une requete sur le descripteur de fichier dans la file avec aio_read(3). Le programme boucle ensuite, en surveillant periodiquement toutes les operations d'E/S en cours avec aio_error(3). Chaque requete d'E/S est configuree pour fournir une notification en distribuant un signal. Quand toutes les requetes d'E/S sont terminees, le programme recupere leur etat avec aio_return(3). Le signal SIGQUIT (cree en tapant Controle-\) provoque la demande d'annulation de chaque requete en cours avec aio_cancel(3). Voici un exemple de ce qui pourrait etre affiche lors de l'execution de ce programme. Dans cet exemple, le programme place en file d'attente deux requetes sur l'entree standard et deux lignes de saisie contenant << abc >> et << x >> y repondent. $ ./a.out /dev/stdin /dev/stdin /dev/stdin ouvert sur le descripteur 3 /dev/stdin ouvert sur le descripteur 4 aio_error(): pour la requete 0 (descripteur 3) : En cours pour la requete 1 (descripteur 4) : En cours abc Signal de fin d'E/S recu aio_error(): pour la requete 0 (descripteur 3) : E/S reussie pour la requete 1 (descripteur 4) : En cours aio_error(): pour la requete 1 (descripteur 4) : En cours x Signal de fin d'E/S recu aio_error(): pour la requete 1 (descripteur 4) : E/S reussie Toutes les requetes d'E/S sont terminees aio_return(): pour la requete 0 (descripteur 3) : 4 pour la requete 1 (descripteur 4) : 2 Source du programme #include #include #include #include #include #include #include #define BUF_SIZE 20 /* Taille des tampons pour les operations de lecture */ #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0) struct ioRequest { /* Structure specifique a l'application pour suivre les requetes d'E/S */ int reqNum; int status; struct aiocb *aiocbp; }; static volatile sig_atomic_t gotSIGQUIT = 0; /* Essayer d'annuler toutes les requetes d'E/S en cours lors de la reception d'un SIGQUIT */ static void /* Gestionnaire pour SIGQUIT */ quitHandler(int sig) { gotSIGQUIT = 1; } #define IO_SIGNAL SIGUSR1 /* Signal pour notifier la fin d'E/S */ static void /* Gestionnaire pour le signal de fin d'E/S */ aioSigHandler(int sig, siginfo_t *si, void *ucontext) { if (si->si_code == SI_ASYNCIO) { write(STDOUT_FILENO, "Gestionnaire pour le signal de fin d'E/S\n", 31); /* La structure ioRequest correspondante serait disponible en struct ioRequest *ioReq = si->si_value.sival_ptr; et le descripteur de fichier serait alors disponible via ioReq->aiocbp->aio_fildes */ } } int main(int argc, char *argv[]) { struct sigaction sa; int s; int numReqs; /* Nombre total de requetes d'E/S dans la file */ int openReqs; /* Nombre de requetes d'E/S encore en cours */ if (argc < 2) { fprintf(stderr, "Utilisation : %s ...\n", argv[0]); exit(EXIT_FAILURE); } numReqs = argc - 1; /* Allocation des tableaux. */ struct ioRequest *ioList = calloc(numReqs, sizeof(*ioList)); if (ioList == NULL) errExit("calloc"); struct aiocb *aiocbList = calloc(numReqs, sizeof(*aiocbList)); if (aiocbList == NULL) errExit("calloc"); /* Mise en place des gestionnaires pour SIGQUIT et le signal de fin d'E/S. */ sa.sa_flags = SA_RESTART; sigemptyset(&sa.sa_mask); sa.sa_handler = quitHandler; if (sigaction(SIGQUIT, &sa, NULL) == -1) errExit("sigaction"); sa.sa_flags = SA_RESTART | SA_SIGINFO; sa.sa_sigaction = aioSigHandler; if (sigaction(IO_SIGNAL, &sa, NULL) == -1) errExit("sigaction"); /* Ouverture de chaque fichier indique sur la ligne de commande et mise en file d'attente d'une requete de lecture sur le descripteur de fichier correspondant. */ for (size_t j = 0; j < numReqs; j++) { ioList[j].reqNum = j; ioList[j].status = EINPROGRESS; ioList[j].aiocbp = &aiocbList[j]; ioList[j].aiocbp->aio_fildes = open(argv[j + 1], O_RDONLY); if (ioList[j].aiocbp->aio_fildes == -1) errExit("open"); printf("%s ouvert sur le descripteur %d\n", argv[j + 1], ioList[j].aiocbp->aio_fildes); ioList[j].aiocbp->aio_buf = malloc(BUF_SIZE); if (ioList[j].aiocbp->aio_buf == NULL) errExit("malloc"); ioList[j].aiocbp->aio_nbytes = BUF_SIZE; ioList[j].aiocbp->aio_reqprio = 0; ioList[j].aiocbp->aio_offset = 0; ioList[j].aiocbp->aio_sigevent.sigev_notify = SIGEV_SIGNAL; ioList[j].aiocbp->aio_sigevent.sigev_signo = IO_SIGNAL; ioList[j].aiocbp->aio_sigevent.sigev_value.sival_ptr = &ioList[j]; s = aio_read(ioList[j].aiocbp); if (s == -1) errExit("aio_read"); } openReqs = numReqs; /* Boucle, surveillance de l'etat des requetes d'E/S. */ while (openReqs > 0) { sleep(3); /* Delai entre chaque etape de surveillance */ if (gotSIGQUIT) { /* Lors de la reception de SIGQUIT, essayer d'annuler toutes les requetes d'E/S en cours et afficher l'etat renvoye par les requetes d'annulation. */ printf("reception de SIGQUIT ; annulation des requetes d'E/S : \n"); for (size_t j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" Request %zu on descriptor %d:", j, ioList[j].aiocbp->aio_fildes); s = aio_cancel(ioList[j].aiocbp->aio_fildes, ioList[j].aiocbp); if (s == AIO_CANCELED) printf("I/O canceled\n"); else if (s == AIO_NOTCANCELED) printf("I/O not canceled\n"); else if (s == AIO_ALLDONE) printf("I/O all done\n"); else perror("aio_cancel"); } } gotSIGQUIT = 0; } /* Verification de l'etat de toutes les requetes d'E/S encore en cours. */ printf("aio_error():\n"); for (size_t j = 0; j < numReqs; j++) { if (ioList[j].status == EINPROGRESS) { printf(" pour la requete %zu (descripteur %d) : ", j, ioList[j].aiocbp->aio_fildes); ioList[j].status = aio_error(ioList[j].aiocbp); switch (ioList[j].status) { case 0: printf("E/S reussie\n"); break; case EINPROGRESS: printf("En cours\n"); break; case ECANCELED: printf("Annulee\n"); break; default: perror("aio_error"); break; } if (ioList[j].status != EINPROGRESS) openReqs--; } } } printf("Toutes les requetes d'E/S sont terminees\n"); /* Verification de l'etat de retour de toutes les requetes d'E/S. */ printf("aio_return():\n"); for (size_t j = 0; j < numReqs; j++) { ssize_t s; s = aio_return(ioList[j].aiocbp); printf(" pour la requete %zu (descripteur %d) : %zd\n", j, ioList[j].aiocbp->aio_fildes, s); } exit(EXIT_SUCCESS); } VOIR AUSSI io_cancel(2), io_destroy(2), io_getevents(2), io_setup(2), io_submit(2), aio_cancel(3), aio_error(3), aio_init(3), aio_read(3), aio_return(3), aio_write(3), lio_listio(3) "Asynchronous I/O Support in Linux 2.5", Bhattacharya, Pratt, Pulavarty, and Morgan, Proceedings of the Linux Symposium, 2003, 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 , Thomas Vincent 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 AIO(7)