1. NOM▲
aio - Vue d'ensemble des entrées-sorties (E/S) asynchrones POSIX
2. 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 champs de cette structure sont les suivants :
- aio_filedes
Le descripteur de 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 :
- aio_init(3)
Configurer les paramètres pour régler le comportement de l'implémentation AIO POSIX de la glibc.
3. 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).
4. VERSIONS ▲
Les interfaces AIO POSIX sont fournies par la glibc depuis la version 2.1.
5. CONFORMITÉ ▲
POSIX.1-2001, POSIX.1-2008.
6. 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.
7. EXEMPLE ▲
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
7.1. Source du programme ▲
#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)
{
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) : %ld
\n
"
,
j, ioList[j].aiocbp->
aio_fildes, (
long
) s);
}
exit
(
EXIT_SUCCESS);
}
8. 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) http://www.squid-cache.org/~adrian/Reprint-Pulavarty-OLS2003.pdf
9. COLOPHON ▲
Cette page fait partie de la publication 3.52 du projet man-pages Linux. Une description du projet et des instructions pour signaler des anomalies peuvent être trouvées à l'adresse http://www.kernel.org/doc/man-pages/.
10. TRADUCTION ▲
Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a <http://po4a.alioth.debian.org/> par l'équipe de traduction francophone au sein du projet perkamon <http://perkamon.alioth.debian.org/>.
Veuillez signaler toute erreur de traduction en écrivant à <>.
Vous pouvez toujours avoir accès à la version anglaise de ce document en utilisant la commande « LC_ALL=C man <section> <page_de_man> ».