Entrées-sorties¶
Introduction¶
Rappel sur les apports d’UNIX¶
- Toute entrée / sortie se fait par le biais d’un « fichier » (du point de vue du programmeur).
- Les ressources d’E/S sont en général matérialisées dans le système de fichiers (répertoire
/dev
pour les périphériques ou devices).
Homogénéité:
- des concepts
- des appels systèmes (
read
,write
,open
,close
,lseek
) - de la gestion des droits d’accès
Notion de fichier¶
Descripteur de fichier¶
Un descripteur de fichier est un entier qui identifie, au sein d’un processus, un fichier ouvert par ce processus.
/* open retourne un descripteur de fichier... */
int open (const char *path, int oflag, [int mode]);
/* ... utilisé ensuite par les fonctions d'E/S */
int read (int fildes, void *buf, int nbyte);
int write(int fildes, void *buf, int nbyte);
int lseek(int fildes, int offset, int whence);
int close(int fildes);
Informations liées à un DF¶
Le système fait correspondre à chaque DF une structure de donnée contenant les informations sur le fichier ouvert :
- type de ressource d’E/S (stockage, périphérique…)
- mode d’ouverture (lecture, ajout, écriture)
- adresse et taille du tampon, le cas échéant
- etc…
Illustration¶
Remarques¶
La structure de données contenant les informations sur le fichier ouvert
- est créée uniquement pour la durée d’ouverture du fichier
- les données persistantes sont stockées ailleurs (dépendant du type de ressource considéré)
- est propre à chaque processus
- un même fichier peut être ouvert en lecture par un processus, et en écriture par une autre
Remarque (suites)¶
La structure de données contenant les informations sur le fichier ouvert
- n’est accessible qu’au système d’exploitation
- consultées / utilisées par les processus par le biais d’appels systèmes
Types de ressources d’E/S¶
- Fichiers « classiques »
- Périphériques
- Flux (character)
- Adressables (block)
- Spéciaux
- Tubes
- Sockets
Fichier « classique »¶
Gérés par le système de fichiers.
char buf[10];
int fd = open("fich1.dat", O_RDONLY);
read(fd, buf, 10);
close(fd);
fd = open("fich2.dat", O_WRONLY);
write(fd, buf, 10);
close(fd);
Périphériques Flux¶
- Également appelés périphériques character
- L’ordre de lecture / écriture est imposé (séquentiel)
int souris = open("/dev/input/mice", O_RDONLY);
int carte_son = open("/dev/dsp", O_WRONLY);
Périphériques Adressables¶
- Également appelés périphériques block
- On peut choisir l’ordre dans lequel on lit / écrit
- Exemples : disque dur, clés USB
int dd = open("/dev/sda1", O_RDWR);
lseek(dd, 10, SEEK_SET);
read(dd, buf, 1);
NB : dans cet exemple, on accède directement au périphérique (sans passer par le système de fichiers)
Périphériques spéciaux¶
/dev/zero
: périphérique de taille non bornée ne contenant que des zéros (“\x0”, pas le chiffre “0”)/dev/random
: périphérique de taille non bornée contenant des valeurs aléatoires (et non reproductibles)/dev/null
: périphérique dans lequel on peut toujours écrire (les données écrites sont perdues)/dev/full
: périphérique toujours plein (toute tentative d’écriture se solde par une erreur)
Tube – Pipe¶
ls -l | grep pchampin
- Ressource virtuelle créée par le système, composée
- d’un fichier ouvert en écriture
- d’un fichier ouvert en lecture
- Une mémoire tampon permet de limiter le risque de blocage des processus utilisant
- NB: les échanges ont bien lieu via la mémoire, sans stockage → rapide
Illustration¶
Remarques¶
Le tube peut être
soit matérialisé dans le système de fichier (
mknod
)NB: simplement pour le nommer, toujours pas de stockage
soit transmis directement par un parent à son/ses enfants
→ pour communiquer entre un père et ses enfants
→ pour communiquer entre enfants d’un même père
Communication père-fils¶
int p[2];
pipe(p);
int pid = fork();
if (pid > 0) write(p[1], data, data_len);
else if (pid == 0) read(p[0], data, data_len);
Socket¶
- Permet de communiquer à travers un réseau
- Homogène à un fichier…
- appels système
read
,write
- appels système
- … mais possédant aussi des appels spécifiques
recv
,send
,recvfrom
,sendto
…
- Cf. module de Programmation réseau (semestre 4)
Descripteurs de fichiers standards¶
Principe¶
- Par convention, les trois premiers descripteurs de fichiers (0, 1 et 2) ont une sémantique particulière : entrée, sortie et erreur standard
- Intéressant pour les programmes orientés « ligne de commande »
- Permet de combiner différents programmes grâce aux redirections
Redirection par programme¶
Appel système dup2
: duplique un descripteur de fichier
fd = obtenir_descripteur(); // open, pipe...
dup2(fd, 1);
close(fd);
execl("prog1", "prog1");
NB: on peut en principe rediriger n’importe quel descripteur de fichier, mais dans ce cas la réutilisabilité est limitée.
Alternatives et optimisation¶
Entrées / sorties asynchrones¶
- Les appels systèmes
read
etwrite
sont dits bloquants : le processus passe dans l’état bloqué jusqu’à l’aboutissement de l’opération. - Il existe une contrepartie non-bloquante ou asynchrone
de ces appels systèmes :
aio_read
etaio_write
.- Ces appels systèmes retournent immédiatement après leur appel, sans bloquer le processus appelant ;
- ils offrent plusieurs méthodes pour « avertir » le processus que l’opération s’est terminée.
L’appel système mmap
¶
- Aligne une partie d’un fichier sur une zone mémoire,
- et assure la synchronisation entre les deux grace au mécanisme de pagination.
- Utilisable avec tout descripteur de fichier addressable :
- fichier de stockage « classique »
- périphérique addressables
- d’autres (que nous verrons plus tard)