stdin, stdout, stderr sind einige Ganzzahlen, die in eine Datenstruktur indizieren, die "weiß", welche E / A-Kanäle für den Prozess verwendet werden sollen. Ich verstehe, dass diese Datenstruktur für jeden Prozess einzigartig ist. Sind E / A-Kanäle nur einige Datenarray-Strukturen mit dynamischer Speicherzuordnung?
8
Antworten:
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 demproc
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ächsteread()
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 indevpts
definierten Dateisystemimplementierung verwaltet/fs/devpts/inode.c
, während der TTY-Treiber, der dasptmx
Gerät im Unix98-Stil bereitstellt , in definiert istdrivers/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 wird
include/linux/tty.h
Vor Kernel Version 3.7 war der Puffer ein Flip-Puffer :
Die Struktur enthielt Speicher, der in zwei gleich große Puffer unterteilt war. Die Puffer wurden nummeriert
0
(erste Hälftechar_buf/flag_buf
) und1
(zweite Hälfte). Der Treiber hat Daten in dem durch gespeicherten Puffer gespeichertbuf_num
. Der andere Puffer könnte in die Leitungsdisziplin gespült werden.Der Puffer wurde durch Umschalten
buf_num
zwischen0
und "umgedreht"1
. Beibuf_num
Änderung wurdechar_buf_ptr
undflag_buf_ptr
auf den Anfang des durchbuf_num
und identifizierten Puffers gesetzt undcount
auf gesetzt0
.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.quelle
Auf den Manpages für eine der drei wird die Antwort erklärt:
quelle
stdin
,stdout
undstderr
aus der Sicht der C - Bibliothek, aber die Frage ist explizit über die Kernel - Implementierung. Ich habe versucht, den Kernel-Standpunkt in meiner Antwort zu berücksichtigen .