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 :
Placer en file d’attente
une requête de lecture. C’est
l’équivalent asynchrone de read(2). Placer en file d’attente
une requête d’écriture. C’est
l’équivalent asynchrone de write(2). 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). Obtenir l’état
d’erreur d’une requête d’E/S
placée en file d’attente. Obtenir l’état de
retour d’une requête d’E/S
terminée. Suspendre l’appelant
jusqu’à la fin d’une ou plusieurs
requêtes d’E/S d’un ensemble
indiqué. Essayer d’annuler des
requêtes d’E/S en cours sur un descripteur de
fichier indiqué. 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 : Les champs de
cette structure sont les suivants : 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(7) 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 les
extensions suivantes à l’API AIO POSIX :
Configurer les
paramètres pour régler le comportement de
l’implémentation AIO POSIX de la glibc. 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). Les interfaces
AIO POSIX sont fournies par la glibc depuis la
version 2.1. POSIX.1-2001,
POSIX.1-2008. 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. 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 Source du
programme 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,
https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf">https://www.kernel.org/doc/ols/2003/ols2003-pages-351-366.pdf Cette page fait
partie de la publication 5.07 du projet
man-pages Linux. Une description du projet et des
instructions pour signaler des anomalies et la
dernière version de cette page, peuvent être
trouvées à l’adresse
https://www.kernel.org/doc/man-pages/. 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 [AT] laposte.net>, Thierry Vignaud
<tvignaud [AT] mandriva.com>, François Micaux, Alain
Portal <aportal [AT] univ-montp2.fr>, Jean-Philippe
Guérard <fevrier [AT] tigreraye.org>, Jean-Luc
Coulon (f5ibh) <jean-luc.coulon [AT] wanadoo.fr>, Julien
Cristau <jcristau [AT] debian.org>, Thomas Huriaux
<thomas.huriaux [AT] gmail.com>, Nicolas François
<nicolas.francois [AT] centraliens.net>, Florentin Duneau
<fduneau [AT] gmail.com>, Simon Paillard
<simon.paillard [AT] resel.fr>, Denis Barbier
<barbier [AT] debian.org> et David Prévot
<david [AT] tilapin.org> 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 à
<debian-l10n-french [AT] lists.org>.
aio_read(3)
#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 };
aio_fildes
aio_init(3)
ERREURS
VERSIONS
CONFORMITÉ
NOTES
EXEMPLES
/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
#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)
#define errMsg(msg) do { perror(msg); } 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, "Signal de fin d’E/S reçu\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 ioRequest *ioList;
struct aiocb *aiocbList;
struct sigaction sa;
int s, j;
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 */
ioList = calloc(numReqs, sizeof(struct ioRequest));
if (ioList == NULL)
errExit("calloc");
aiocbList = calloc(numReqs, sizeof(struct aiocb));
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 (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 (j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" Requête %d sur le descripteur %d :", j,
ioList[j].aiocbp->aio_fildes);
s = aio_cancel(ioList[j].aiocbp->aio_fildes,
ioList[j].aiocbp);
if (s == AIO_CANCELED)
printf("E/S annulée\n");
else if (s == AIO_NOTCANCELED)
printf("E/S non annulée\n");
else if (s == AIO_ALLDONE)
printf("E/S terminée\n");
else
errMsg("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 (j = 0; j < numReqs; j++) {
if (ioList[j].status == EINPROGRESS) {
printf(" pour la requête %d (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:
errMsg("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 (j = 0; j < numReqs; j++) {
ssize_t s;
s = aio_return(ioList[j].aiocbp);
printf(" pour la requête %d (descripteur %d) : %zd\n",
j, ioList[j].aiocbp->aio_fildes, s);
}
exit(EXIT_SUCCESS);
}
VOIR AUSSI
COLOPHON
TRADUCTION