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 proc
systè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/pts
ré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 SIGINT
signal 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 0
lorsqu'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 ssh
faire 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 expect
de piloter un programme orienté terminal interactif à partir d'un script.
Ils sont utilisés par les émulateurs de terminaux xterm
afin de fournir des fonctionnalités liées aux terminaux.
Ils sont utilisés par des programmes tels que screen
le multiplexage d'un seul terminal physique entre plusieurs processus.
Ils sont utilisés par des programmes comme script
pour 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/ptmx
sur lequel il reçoit un descripteur de fichier pour un PTM et un dispositif PTS est créé dans le /dev/pts
répertoire. Chaque descripteur de fichier obtenu par ouverture /dev/ptmx
est 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/pts
sont gérés par l' devpts
implé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 ptmx
est 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_num
entre 0
et 1
. Une fois buf_num
modifié, char_buf_ptr
et 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.