In Unix-artigen Betriebssystemen, die Standard - Eingabe, Ausgabe und Fehlerströme , die durch die Datei - Deskriptoren bezeichnet sind 0
, 1
, 2
. Unter Linux sind diese unter dem proc
Dateisystem in sichtbar /proc/[pid]/fs/{0,1,2}
. Diese Dateien sind eigentlich symbolische Links zu einem Pseudoterminal- Gerät unter dem /dev/pts
Verzeichnis.
Ein Pseudoterminal (PTY) ist ein Paar virtueller Geräte, ein Pseudoterminal-Master (PTM) und ein Pseudoterminal-Slave (PTS) (zusammen als Pseudoterminal-Paar bezeichnet ), die einen IPC-Kanal bereitstellen, ähnlich einer bidirektionalen Pipe zwischen einem Programm, das dies erwartet verbunden mit einem Endgerät und einem Treiberprogramm, das das Pseudoterminal verwendet, um Eingaben an das vorherige Programm zu senden und Eingaben von diesem zu empfangen.
Ein wichtiger Punkt ist, dass der Pseudoterminal-Slave wie ein reguläres Terminal erscheint, z. B. kann er zwischen nicht- kanonischem und kanonischem Modus (Standardeinstellung) umgeschaltet werden , in dem er bestimmte Eingabezeichen interpretiert, z. B. das Erzeugen eines SIGINT
Signals, wenn ein Interrupt- Zeichen (normalerweise generiert) durch Drücken von Ctrl+ Cauf der Tastatur) wird in den Pseudoterminal-Master geschrieben oder bewirkt, dass der nächste read()
zurückkehrt, 0
wenn ein Zeichen für das Dateiende (normalerweise durch Ctrl+ generiert D) auftritt. Andere von Terminals unterstützte Vorgänge sind das Ein- oder Ausschalten des Echos, das Festlegen der Prozessgruppe im Vordergrund usw.
Pseudoterminale haben eine Reihe von Verwendungsmöglichkeiten:
Sie ermöglichen es Programmen ssh
, terminalorientierte Programme auf einem anderen Host zu betreiben, der über ein Netzwerk verbunden ist. Ein terminalorientiertes Programm kann ein beliebiges Programm sein, das normalerweise in einer interaktiven Terminalsitzung ausgeführt wird. Die Standardeingabe, -ausgabe und -fehler eines solchen Programms können nicht direkt an den Socket angeschlossen werden, da die Sockel die oben genannten terminalbezogenen Funktionen nicht unterstützen.
Sie ermöglichen es Programmen expect
, ein interaktives terminalorientiertes Programm über ein Skript zu steuern.
Sie werden von Terminalemulatoren verwendet xterm
, um terminalbezogene Funktionen bereitzustellen.
Sie werden von Programmen verwendet, um beispielsweise screen
ein einzelnes physisches Terminal zwischen mehreren Prozessen zu multiplexen.
Sie werden von Programmen verwendet script
, um alle Ein- und Ausgaben aufzuzeichnen, die während einer Shell-Sitzung auftreten.
PTYs im Unix98-Stil , die unter Linux verwendet werden, werden wie folgt eingerichtet:
Das Treiberprogramm öffnet den Pseudo-Terminal-Master-Multiplexer dev/ptmx
, an dem es einen Dateideskriptor für ein PTM empfängt, und ein PTS-Gerät wird im /dev/pts
Verzeichnis erstellt. Jeder durch Öffnen erhaltene Dateideskriptor /dev/ptmx
ist ein unabhängiges PTM mit einem eigenen zugeordneten PTS.
Die Treiberprogramme rufen fork()
auf, um einen untergeordneten Prozess zu erstellen, der wiederum die folgenden Schritte ausführt:
Das Kind ruft setsid()
an, um eine neue Sitzung zu starten, deren Sitzungsleiter das Kind ist. Dies führt auch dazu, dass das Kind sein Kontrollterminal verliert .
Das Kind öffnet das PTS-Gerät, das dem vom Treiberprogramm erstellten PTM entspricht. Da das Kind ein Sitzungsleiter ist, aber kein steuerndes Terminal hat, wird das PTS zum steuernden Terminal des Kindes.
Das Kind verwendet dup()
, um den Dateideskriptor für das Slave-Gerät auf der Standardeingabe, -ausgabe und dem Fehler zu duplizieren.
Zuletzt ruft das Kind exec()
auf, um das terminalorientierte Programm zu starten, das mit dem Pseudoterminalgerät verbunden werden soll.
Zu diesem Zeitpunkt wird alles, was das Treiberprogramm in das PTM schreibt, als Eingabe für das terminalorientierte Programm auf dem PTS angezeigt und umgekehrt.
Im kanonischen Modus wird der Eingang zum PTS zeilenweise gepuffert. Mit anderen Worten, genau wie bei regulären Terminals erhält das von einem PTS gelesene Programm nur dann eine Eingabezeile, wenn ein Zeilenumbruchzeichen in das PTM geschrieben wird. Wenn die Pufferkapazität erschöpft ist, write()
blockieren weitere Aufrufe, bis ein Teil der Eingabe verbraucht ist.
Im Linux - Kernel, die Datei im Zusammenhang Systemaufrufe open()
, read()
, write()
stat()
etc. sind in der virtuellen Dateisystem (VFS) Schicht implementiert, die für Userspace - Programme einen einheitlichen Dateisystem - Schnittstelle zur Verfügung stellt. Das VFS ermöglicht die Koexistenz verschiedener Dateisystemimplementierungen innerhalb des Kernels. Wenn Userspace-Programme die oben genannten Systemaufrufe aufrufen, leitet das VFS den Aufruf an die entsprechende Dateisystemimplementierung weiter.
Die PTS-Geräte unter /dev/pts
werden von der in devpts
definierten Dateisystemimplementierung verwaltet /fs/devpts/inode.c
, während der TTY-Treiber, der das ptmx
Gerät im Unix98-Stil bereitstellt , in definiert ist drivers/tty/pty.c
.
Das Puffern zwischen TTY-Geräten und TTY- Leitungsdisziplinen , wie z. B. Pseudoterminals, wird mit einer Pufferstruktur bereitgestellt, die für jedes in definierte tty-Gerät verwaltet wirdinclude/linux/tty.h
Vor Kernel Version 3.7 war der Puffer ein Flip-Puffer :
#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];
};
Die Struktur enthielt Speicher, der in zwei gleich große Puffer unterteilt war. Die Puffer wurden nummeriert 0
(erste Hälfte char_buf/flag_buf
) und 1
(zweite Hälfte). Der Treiber hat Daten in dem durch gespeicherten Puffer gespeichert buf_num
. Der andere Puffer könnte in die Leitungsdisziplin gespült werden.
Der Puffer wurde durch Umschalten buf_num
zwischen 0
und "umgedreht" 1
. Bei buf_num
Änderung wurde char_buf_ptr
und flag_buf_ptr
auf den Anfang des durch buf_num
und identifizierten Puffers gesetzt und count
auf gesetzt 0
.
Seit der Kernel-Version 3.7 wurden die TTY-Flip-Puffer durch Objekte ersetzt, die über kmalloc()
in Ringen organisierte Objekte zugewiesen wurden . In einer normalen Situation für eine IRQ-gesteuerte serielle Schnittstelle bei typischen Geschwindigkeiten ist ihr Verhalten ziemlich das gleiche wie beim alten Flip-Buffer. Am Ende werden zwei Puffer zugewiesen, und der Kernel wechselt wie zuvor zwischen ihnen. Wenn es jedoch zu Verzögerungen kommt oder die Geschwindigkeit zunimmt, ist die Leistung der neuen Pufferimplementierung besser, da der Pufferpool etwas wachsen kann.