Ich habe nachgelesen, wie Pipes im Linux-Kernel implementiert sind, und wollte mein Verständnis überprüfen. Wenn ich falsch liege, wird die Antwort mit der richtigen Erklärung ausgewählt.
- Linux hat ein VFS namens pipefs, das im Kernel eingehängt ist (nicht im User Space)
- pipefs hat einen einzelnen Superblock und wird daneben an seiner eigenen root (
pipe:
) gemountet/
- Pipefs können im Gegensatz zu den meisten Dateisystemen nicht direkt angezeigt werden
- Der Zugang zu pipefs erfolgt über den
pipe(2)
Syscall - Der
pipe(2)
Systemaufruf, der von Shells für die Weiterleitung an den|
Operator (oder manuell von einem anderen Prozess) verwendet wird, erstellt eine neue Datei in Pipefs, die sich so ziemlich wie eine normale Datei verhält - Die Datei auf der linken Seite des Pipe-Operators wird
stdout
in die temporäre Datei umgeleitet, die in pipefs erstellt wurde - Die Datei auf der rechten Seite des Pipe-Operators ist
stdin
auf die Datei auf Pipefs eingestellt - pipefs ist im Speicher gespeichert und sollte durch Kernelmagie nicht ausgelagert werden
Ist diese Erklärung, wie Pipes (z. B. ls -la | less
) funktionieren, ziemlich korrekt?
Eine Sache, die ich nicht verstehe, ist, wie so etwas wie Bash einen Prozess stdin
oder stdout
den von zurückgegebenen Dateideskriptor setzen würde pipe(2)
. Darüber habe ich noch nichts gefunden.
pipe()
Kernel-Aufruf ist zusammen mit der Maschinerie, die ihn unterstützt (pipefs
usw.), viel niedriger als der|
Operator, der in Ihrer Shell angeboten wird. Letzteres wird normalerweise mit dem ersteren implementiert, muss es aber nicht sein.|
Operator nurpipe(2)
als ein Prozess aufruft , wie es Bash tut.Antworten:
Ihre bisherige Analyse ist im Allgemeinen richtig. Die Art und Weise, wie eine Shell den Standardwert eines Prozesses auf einen Pipe-Deskriptor setzt, könnte sein (Pseudocode):
quelle
dup2
Aufruf benötigt wird, und Sie können den Pipe-Deskriptor nicht einfach direkt stdin zuweisen?pipe()
. Derdup2()
Aufruf ermöglicht dem Aufrufer, den Dateideskriptor auf einen bestimmten numerischen Wert zu kopieren (erforderlich, da 0, 1, 2 stdin, stdout, stderr sind). Das ist das Kernel-Äquivalent von "stdin direkt zuweisen". Beachten Sie, dass die globale Variable der C-Laufzeitbibliothek eine Variablestdin
istFILE *
, die nicht kernelbezogen ist (obwohl sie für die Verbindung mit Deskriptor 0 initialisiert wurde).dup2
Aufruf wird nicht geändertp[1]
. Stattdessen werden die beiden Ziehpunkte erstelltp[1]
und0
auf dasselbe Kernelobjekt (die Pipe) verwiesen. Da der untergeordnete Prozess keine zwei Standard-Handles benötigt (und ohnehin nicht wissen würde, was das nummerierte Handlep[1]
ist),p[1]
wird er zuvor geschlossenexec
.