:tocdepth: 2 ================= Entrées-sorties ================= .. include:: common.rst.inc 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 ================= .. index:: pair: appel système; open pair: appel système; read pair: appel système; write pair: appel système; lseek pair: appel système; close .. index:: descripteur de fichier single: fichier; descripteur Descripteur de fichier ++++++++++++++++++++++ Un **descripteur de fichier** est un entier qui identifie, *au sein d'un processus*, un fichier ouvert par ce processus. .. code-block:: c /* 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 ------------ .. figure:: _static/es_filedescriptors.png :width: 100% 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 `:doc:. .. code-block:: c 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) .. code-block:: c 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 .. code-block:: c int dd = open("/dev/sda1", O_RDWR); lseek(dd, 10, SEEK_SET); read(dd, buf, 1); .. rst-class:: small 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) .. index:: tube see: pipe; tube Tube – Pipe +++++++++++ .. code-block:: sh 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 ------------ .. figure:: _static/es_pipe.png :width: 100% 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 .. index:: pair: appel système; pipe Communication père-fils ----------------------- .. code-block:: c 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`` * ... mais possédant aussi des appels spécifiques * ``recv``, ``send``, ``recvfrom``, ``sendto``... * Cf. module de Programmation réseau (semestre 4) .. index:: single: descripteur de fichier; standard single: fichier; descripteurs standards 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** .. index:: redirection Redirection des E/S standard ---------------------------- .. code-block:: sh prog1 fich2 ou .. code-block:: sh prog1 | prog2 | prog3 .. index:: pair: appel système; dup2 Redirection par programme ------------------------- Appel système ``dup2``: duplique un descripteur de fichier .. code-block:: c 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. .. index:: single: entrées / sorties; asynchrones pair: appel système; aio_read pair: appel système; aio_write Alternatives et optimisation ============================ Entrées / sorties asynchrones +++++++++++++++++++++++++++++ * Les appels systèmes ``read`` et ``write`` 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`` et ``aio_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. .. index:: pair: appel système; mmap 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 `:doc:. * Utilisable avec tout descripteur de fichier *addressable* : * fichier de stockage « classique » * périphérique addressables * d'autres (que nous verrons `plus tard `:ref:)