AIO
Table des matières
Retour à l'index
NOM
aio - Vue d'ensemble des entrées-sorties (E/S) asynchrones POSIX
DESCRIPTION
L'interface d'E/S asynchrones (AIO pour « asynchronous I/O ») POSIX permet
aux applications de déclencher une ou plusieurs opérations d'E/S réalisées
de façon asynchrone (c'est-à-dire en arrière-plan). La fin d'une opération
d'E/S peut être notifiée à l'application de différentes façons au choix :
distribution d'un signal, instanciation d'un thread ou absence de
notification.
L'interface AIO POSIX est composée des fonctions suivantes :
- aio_read(3)
-
Placer en file d'attente une requête de lecture. C'est l'équivalent
asynchrone de read(2).
- aio_write(3)
-
Placer en file d'attente une requête d'écriture. C'est l'équivalent
asynchrone de write(2).
- aio_fsync(3)
-
Placer en file d'attente une requête de synchronisation pour des opérations
d'E/S sur un descripteur de fichier. C'est l'équivalent asynchrone de
fsync(2) et fdatasync(2).
- aio_error(3)
-
Obtenir l'état d'erreur d'une requête d'E/S placée en file d'attente.
- aio_return(3)
-
Obtenir l'état de retour d'une requête d'E/S terminée.
- aio_suspend(3)
-
Suspendre l'appelant jusqu'à la fin d'une ou plusieurs requêtes d'E/S d'un
ensemble indiqué.
- aio_cancel(3)
-
Essayer d'annuler des requêtes d'E/S en cours sur un descripteur de fichier
indiqué.
- lio_listio(3)
-
Placer en file d'attente plusieurs requêtes d'E/S à partir d'un seul appel
de fonction.
La structure aiocb (« asynchronous I/O control block », ou bloc de
contrôle d'E/S asynchrones) définit les paramètres de contrôle d'une
opération d'E/S. Un argument de ce type est utilisé avec toutes les
fonctions précédentes. Cette structure est de la forme suivante :
#include <aiocb.h>
struct aiocb {
/* L'ordre de ces champs dépend de l'implémentation */
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; /* Priorité de requête */
struct sigevent aio_sigevent; /* Méthode de notification */
int aio_lio_opcode; /* Opération à réaliser ;
lio_listio() seulement */
/* Divers champs internes à l'implémentation ne sont pas montrés */
};
/* Codes opératoires 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 opérations d'E/S sont à réaliser.
- aio_offset
-
La position dans le fichier où les opérations d'E/S sont à réaliser.
- aio_buf
-
Le tampon utilisé pour le transfert de données des opérations de lecture ou
d'écriture.
- aio_nbytes
-
La taille du tampon pointé par aio_buf.
- aio_reqprio
-
Valeur à soustraire de la priorité temps-réel du thread de l'appelant pour
déterminer la priorité d'exécution de cette requête d'E/S (consultez
pthread_setschedparam(3)). La valeur indiquée doit être entre 0 et la
valeur renvoyée par sysconf(_SC_AIO_PRIO_DELTA_MAX). Ce champ est ignoré
lors des opérations de synchronisation de fichier.
- aio_sigevent
-
Structure indiquant comment l'appelant sera notifié de la fin d'une
opération d'E/S asynchrone. Les valeurs de aio_sigevent.sigev_notify
peuvent être SIGEV_NONE, SIGEV_SIGNAL et SIGEV_THREAD. Consultez
sigevent(3type) pour plus de précisions.
- aio_lio_opcode
-
Le type d'opération à réaliser, utilisé seulement pour lio_listio(3).
En plus des fonctions standard précédentes, la bibliothèque C du projet GNU
fournit l'extension suivante à l'API AIO POSIX :
- aio_init(3)
-
Configurer les paramètres pour régler le comportement de l'implémentation
AIO POSIX de la glibc.
ERREURS
- EINVAL
-
Le champ aio_reqprio de la structure aiocb était inférieur à 0 ou
supérieur à la limite renvoyée par l'appel
sysconf(_SC_AIO_PRIO_DELTA_MAX).
STANDARDS
POSIX.1-2008.
HISTORIQUE
POSIX.1-2001. glibc 2.1.
NOTES
Il est conseillé de mettre à zéro le tampon de bloc de contrôle avant
utilisation (consultez memset(3)). Le tampon de bloc de contrôle et le
tampon pointé par aio_buf ne doivent pas être modifiés pendant
l'exécution d'une opération d'E/S. Ces tampons doivent rester valables
jusqu'à la fin de l'opération d'E/S.
Les opérations de lecture ou d'écriture asynchrones simultanées qui
utilisent la même structure aiocb produisent des résultats indéfinis.
L'actuelle implémentation AIO POSIX de Linux est fournie en espace
utilisateur par la glibc. De nombreuses limites existent, en particulier le
maintien de plusieurs threads pour réaliser des opérations d'E/S est très
coûteux et monte mal en charge. L'implémentation d'E/S asynchrones basée sur
l'état 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 implémentation n'a pas encore atteint le
niveau où l'implémentation AIO POSIX peut être entièrement réimplémentée en
utilisant les appels système du noyau.
EXEMPLES
Le programme suivant ouvre chaque fichier nommé en argument de sa ligne de
commande et place une requête sur le descripteur de fichier dans la file
avec aio_read(3). Le programme boucle ensuite, en surveillant
périodiquement toutes les opérations d'E/S en cours avec
aio_error(3). Chaque requête d'E/S est configurée pour fournir une
notification en distribuant un signal. Quand toutes les requêtes d'E/S sont
terminées, le programme récupère leur état avec aio_return(3).
Le signal SIGQUIT (créé en tapant Contrôle-\) provoque la demande
d'annulation de chaque requête en cours avec aio_cancel(3).
Voici un exemple de ce qui pourrait être affiché lors de l'exécution de ce
programme. Dans cet exemple, le programme place en file d'attente deux
requêtes sur l'entrée standard et deux lignes de saisie contenant « abc » et
« x » y répondent.
$ ./a.out /dev/stdin /dev/stdin
/dev/stdin ouvert sur le descripteur 3
/dev/stdin ouvert sur le descripteur 4
aio_error():
pour la requête 0 (descripteur 3) : En cours
pour la requête 1 (descripteur 4) : En cours
abc
Signal de fin d'E/S reçu
aio_error():
pour la requête 0 (descripteur 3) : E/S réussie
pour la requête 1 (descripteur 4) : En cours
aio_error():
pour la requête 1 (descripteur 4) : En cours
x
Signal de fin d'E/S reçu
aio_error():
pour la requête 1 (descripteur 4) : E/S réussie
Toutes les requêtes d'E/S sont terminées
aio_return():
pour la requête 0 (descripteur 3) : 4
pour la requête 1 (descripteur 4) : 2
Source du programme
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <aio.h>
#include <signal.h>
#define BUF_SIZE 20 /* Taille des tampons pour les opérations de lecture */
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
struct ioRequest { /* Structure spécifique à l'application
pour suivre les requêtes d'E/S */
int reqNum;
int status;
struct aiocb *aiocbp;
};
static volatile sig_atomic_t gotSIGQUIT = 0;
/* Essayer d'annuler toutes les requêtes d'E/S
en cours lors de la réception 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 requêtes d'E/S dans la file */
int openReqs; /* Nombre de requêtes d'E/S encore en cours */
if (argc < 2) {
fprintf(stderr, "Utilisation : %s <chemin> <chemin>...\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 indiqué sur la ligne de commande et mise en file
d'attente d'une requête 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'état des requêtes d'E/S. */
while (openReqs > 0) {
sleep(3); /* Délai entre chaque étape de surveillance */
if (gotSIGQUIT) {
/* Lors de la réception de SIGQUIT, essayer d'annuler
toutes les requêtes d'E/S en cours et afficher
l'état renvoyé par les requêtes d'annulation. */
printf("réception de SIGQUIT ; annulation des requêtes 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;
}
/* Vérification de l'état de toutes les
requêtes 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 requête %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 réussie\n");
break;
case EINPROGRESS:
printf("En cours\n");
break;
case ECANCELED:
printf("Annulée\n");
break;
default:
perror("aio_error");
break;
}
if (ioList[j].status != EINPROGRESS)
openReqs--;
}
}
}
printf("Toutes les requêtes d'E/S sont terminées\n");
/* Vérification de l'état de retour de toutes les requêtes 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 requête %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 française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.rafin@laposte.net>,
Thierry Vignaud <tvignaud@mandriva.com>,
François Micaux,
Alain Portal <aportal@univ-montp2.fr>,
Jean-Philippe Guérard <fevrier@tigreraye.org>,
Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>,
Thomas Vincent <tvincent@debian.org>
et
Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>
Cette traduction est une documentation libre ; veuillez vous reporter à la
GNU General Public License version 3
concernant les conditions de copie et
de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
Index
- NOM
-
- DESCRIPTION
-
- ERREURS
-
- STANDARDS
-
- HISTORIQUE
-
- NOTES
-
- EXEMPLES
-
- Source du programme
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 05:06:36 GMT, September 19, 2025