Comment les canaux d'E / S sont-ils implémentés dans le noyau Linux?

8

stdin, stdout, stderr sont des entiers qui indexent dans une structure de données qui «sait» quels canaux d'E / S doivent être utilisés pour le processus. Je comprends que cette structure de données est propre à chaque processus. Les canaux d'E / S ne sont-ils que des structures de tableaux de données avec allocation dynamique de mémoire?

KawaiKx
la source
par canaux d'E / S, voulez-vous dire des flux ou des tuyaux? aussi, cela varie probablement selon le noyau. vous devrez probablement vous renseigner sur un noyau spécifique.
strugee
1
@strugee Je parle du noyau Linux. Je voulais dire les flux par canaux d'E / S. Comment ces flux sont-ils mis en œuvre sous Linux? un tableau ou quelque chose?
KawaiKx

Réponses:

14

Dans Unix systèmes d' exploitation, l'entrée standard, de sortie et les flux d' erreur sont identifiés par les descripteurs de fichiers 0, 1, 2. Sous Linux, ceux-ci sont visibles sous le procsystème de fichiers dans /proc/[pid]/fs/{0,1,2}. Ces fichiers sont en fait des liens symboliques vers un périphérique pseudoterminal sous le /dev/ptsrépertoire.

Un pseudoterminal (PTY) est une paire de dispositifs virtuels, un pseudoterminal master (PTM) et un pseudoterminal slave (PTS) (collectivement appelés pseudoterminal pair ), qui fournissent un canal IPC, un peu comme un tuyau bidirectionnel entre un programme qui attend à connecter à un terminal et à un programme pilote qui utilise le pseudoterminal pour envoyer et recevoir des données de l'ancien programme.

Un point clé est que l'esclave pseudoterminal apparaît comme un terminal normal, par exemple, il peut basculer entre le mode non canonique et canonique (par défaut), dans lequel il interprète certains caractères d'entrée, comme générer un SIGINTsignal lorsqu'un caractère d' interruption (généré normalement en appuyant sur Ctrl+ Csur le clavier) est écrit sur le maître pseudoterminal ou provoque le read()retour du suivant 0lorsqu'un caractère de fin de fichier (normalement généré par Ctrl+ D) est rencontré. D'autres opérations prises en charge par les terminaux activent ou désactivent l'écho, définissent le groupe de processus de premier plan, etc.

Les pseudoterminaux ont un certain nombre d'utilisations:

  • Ils permettent à des programmes comme de sshfaire fonctionner des programmes orientés terminal sur un autre hôte connecté via un réseau. Un programme orienté terminal peut être n'importe quel programme, qui serait normalement exécuté dans une session de terminal interactif. L'entrée, la sortie et l'erreur standard d'un tel programme ne peuvent pas être connectées directement à la prise, car les prises ne prennent pas en charge la fonctionnalité liée au terminal susmentionnée.

  • Ils permettent à des programmes comme expectde piloter un programme orienté terminal interactif à partir d'un script.

  • Ils sont utilisés par les émulateurs de terminaux xtermafin de fournir des fonctionnalités liées aux terminaux.

  • Ils sont utilisés par des programmes tels que screenle multiplexage d'un seul terminal physique entre plusieurs processus.

  • Ils sont utilisés par des programmes comme scriptpour enregistrer toutes les entrées et sorties se produisant pendant une session shell.

Les PTY de style Unix98 , utilisés sous Linux, sont configurés comme suit:

  • Le programme pilote ouvre le multiplexeur maître pseudo-terminal dev/ptmxsur lequel il reçoit un descripteur de fichier pour un PTM et un dispositif PTS est créé dans le /dev/ptsrépertoire. Chaque descripteur de fichier obtenu par ouverture /dev/ptmxest un PTM indépendant avec son propre PTS associé.

  • Le pilote programme des appels fork()pour créer un processus enfant, qui à son tour effectue les étapes suivantes:

    • L'enfant appelle setsid()pour démarrer une nouvelle session, dont l'enfant est le chef de session. Cela fait également perdre à l'enfant son terminal de contrôle .

    • L'enfant procède à l'ouverture du dispositif PTS qui correspond au PTM créé par le programme pilote. Étant donné que l'enfant est un chef de session, mais n'a pas de terminal de contrôle, le PTS devient le terminal de contrôle de l'enfant.

    • L'enfant utilise dup()pour dupliquer le descripteur de fichier du périphérique esclave sur l'entrée, la sortie et l'erreur standard.

    • Enfin, l'enfant appelle exec()pour démarrer le programme orienté terminal qui doit être connecté au dispositif pseudoterminal.

À ce stade, tout ce que le programme pilote écrit sur le PTM apparaît en tant qu'entrée dans le programme orienté terminal sur le PTS, et vice versa.

En fonctionnement en mode canonique, l'entrée du PTS est mise en mémoire tampon ligne par ligne. En d'autres termes, tout comme avec les terminaux normaux, la lecture de programme à partir d'un PTS ne reçoit une ligne d'entrée que lorsqu'un caractère de nouvelle ligne est écrit dans le PTM. Lorsque la capacité de mise en mémoire tampon est épuisée, d'autres write()appels bloquent jusqu'à ce qu'une partie de l'entrée ait été consommée.

Dans le noyau Linux, les appels système de fichiers liés open(), read(), write() stat()etc. sont mis en œuvre dans la couche virtuelle Filesystem (VFS), qui fournit une interface de système de fichiers uniforme pour les programmes de l' espace utilisateur. Le VFS permet à différentes implémentations de système de fichiers de coexister dans le noyau. Lorsque les programmes de l'espace utilisateur appellent les appels système susmentionnés, le VFS redirige l'appel vers l'implémentation du système de fichiers appropriée.

Les périphériques PTS sous /dev/ptssont gérés par l' devptsimplémentation du système de fichiers définie dans /fs/devpts/inode.c, tandis que le pilote TTY fournissant le périphérique de style Unix98 ptmxest défini dans dans drivers/tty/pty.c.

La mise en mémoire tampon entre les appareils TTY et les disciplines de ligne TTY , telles que les pseudoterminaux, est fournie une structure de mémoire tampon maintenue pour chaque appareil tty, définie dansinclude/linux/tty.h

Avant la version 3.7 du noyau, le tampon était un tampon inversé :

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

La structure contenait un stockage divisé en deux tampons de taille égale. Les tampons ont été numérotés 0(première moitié de char_buf/flag_buf) et 1(seconde moitié). Le pilote a stocké les données dans le tampon identifié par buf_num. L'autre tampon pourrait être vidé de la discipline de ligne.

Le tampon a été inversé en basculant buf_numentre 0et 1. Une fois buf_nummodifié, char_buf_ptret a flag_buf_ptr été défini au début du tampon identifié par buf_num, et a countété défini sur 0.

Depuis la version 3.7 du noyau, les tampons de retournement TTY ont été remplacés par des objets alloués via kmalloc()organisés en anneaux . Dans une situation normale pour un port série piloté par IRQ à des vitesses typiques, leur comportement est à peu près le même qu'avec l'ancien tampon flip; deux tampons finissent par être alloués et le noyau passe entre eux comme précédemment. Cependant, lorsqu'il y a des retards ou que la vitesse augmente, la nouvelle implémentation de tampon fonctionne mieux car le pool de tampons peut augmenter un peu.

Thomas Nyman
la source
Des réponses aussi bien informées que cela sont extrêmement difficiles à trouver.
étale-cohomologie
-1

À partir des pages de manuel de l'un des trois, il explique la réponse:

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.
Jeight
la source
Cette réponse décrit la mise en œuvre stdin, stdoutet stderrdu point de vue de la bibliothèque C, mais la question est explicitement à propos de la mise en œuvre du noyau. J'ai essayé de tenir compte du point de vue du noyau dans ma réponse .
Thomas Nyman