table of contents
other sections
| AIO(7) | Manuel du programmeur Linux | AIO(7) |
NOM¶
aio - Vue d'ensemble des entrées-sorties (E/S) asynchrones POSIXDESCRIPTION¶
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.- 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.
#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).
- aio_init(3)
- Configurer les paramètres pour régler le comportement de l'implémentation AIO POSIX de la glibc.
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.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).
VERSIONS¶
Les interfaces AIO POSIX sont fournies par la glibc depuis la version 2.1.CONFORMITɶ
POSIX.1-2001, POSIX.1-2008.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).$ ./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 <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);
}
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)COLOPHON¶
Cette page fait partie de la publication 3.44 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/>.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 à <debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le paquet manpages-fr. Vous pouvez toujours avoir accès à la version anglaise de ce document en utilisant la commande « man -L C <section> <page_de_man> ».| 5 août 2012 | Linux |