Pipes & fd-Duplikation (WP-2): Erstellt unidirektionale anonyme Pipes für die Prozesskommunikation und dupliziert Dateideskriptoren (dup/dup2/dup3). Typischer Einsatz: Eltern-Kind-Kommunikation nach fork, Stdout/Stderr-Umleitung und Pipe-Kaskaden.
→ Standard Library · std.process · std.mqueue
Alle Konstanten dieser Unit:
| Konstante | Wert | Beschreibung |
|---|---|---|
O_CLOEXEC | 524288 | fd bei exec() schließen (0x80000) |
O_NONBLOCK | 2048 | Pipe-fds nicht-blockierend (0x800) |
Alle öffentlichen Funktionen dieser Unit im Überblick:
Übersicht:
| Signatur | Beschreibung |
|---|---|
PipeCreate(readFdOut: int64, writeFdOut: int64): int64 | Erstellt ein Pipe-Paar. readFdOut und writeFdOut sind je alloc(8)-Buffer; nach Aufruf via peek64 lesen. Gibt 0 bei Erfolg zurück |
Pipe2(readFdOut: int64, writeFdOut: int64, flags: int64): int64 | Wie PipeCreate, aber mit Flags (O_CLOEXEC, O_NONBLOCK oder Kombination) |
Übersicht:
| Signatur | Beschreibung |
|---|---|
FdDup(oldFd: int64): int64 | Dupliziert oldFd auf den nächst-freien fd. Gibt den neuen fd zurück |
FdDup2(oldFd: int64, newFd: int64): int64 | Dupliziert oldFd auf newFd (schließt newFd falls bereits offen). Gibt newFd zurück |
FdDup3(oldFd: int64, newFd: int64, flags: int64): int64 | Wie FdDup2, aber mit Flags (z. B. O_CLOEXEC) |
Grundlegendes Anwendungsbeispiel:
Beispiel:
import std.pipe;
import std.process;
import std.alloc;
import std.io;
fn Main(): void {
var rBuf: int64 := alloc(8);
var wBuf: int64 := alloc(8);
PipeCreate(rBuf, wBuf);
var rFd := peek64(rBuf);
var wFd := peek64(wBuf);
free(rBuf, 8);
free(wBuf, 8);
var pid := Fork();
if (pid == 0) {
// Kindprozess: liest von der Pipe
close(wFd);
var buf: int64 := alloc(64);
var n := read(rFd, buf, 64);
PrintLn("Kind empfing: " + buf as pchar);
free(buf, 64);
close(rFd);
} else {
// Elternprozess: schreibt in die Pipe
close(rFd);
var msg: pchar := "Hallo Kind";
write(wFd, msg as int64, 11);
close(wFd);
Wait(pid);
}
}
Beispiel:
import std.pipe;
import std.alloc;
fn RedirectStdout(): int64 {
var rBuf: int64 := alloc(8);
var wBuf: int64 := alloc(8);
Pipe2(rBuf, wBuf, O_CLOEXEC);
var rFd := peek64(rBuf);
var wFd := peek64(wBuf);
free(rBuf, 8);
free(wBuf, 8);
// fd 1 (stdout) auf Schreib-Ende der Pipe umleiten
FdDup2(wFd, 1);
close(wFd);
// Alles was jetzt über fd 1 geschrieben wird, landet in der Pipe.
// Lese-Ende (rFd) zurückgeben.
return rFd;
}
Beispiel:
import std.pipe;
import std.alloc;
import std.io;
fn TryRead(pipeFd: int64): bool {
var buf: int64 := alloc(256);
var n := read(pipeFd, buf, 256);
free(buf, 256);
if (n < 0) {
// n == -11 bedeutet EAGAIN — keine Daten vorhanden
return false;
}
return true;
}
fn SetupNonblocking(): int64 {
var rBuf: int64 := alloc(8);
var wBuf: int64 := alloc(8);
Pipe2(rBuf, wBuf, O_NONBLOCK | O_CLOEXEC);
var rFd := peek64(rBuf);
free(rBuf, 8);
free(wBuf, 8);
return rFd;
}
Wichtige Hinweise für den Einsatz dieser Unit:
wFd) und Lese-Ende (rFd) müssen nach fork() im jeweils nicht-verwendenden Prozess geschlossen werden — sonst blockiert read auf rFd ewig (Schreib-Ende noch offen).write auf eine volle Pipe blockiert; read auf eine leere Pipe blockiert.O_NONBLOCK geben read/write sofort zurück: −11 (EAGAIN) wenn nicht bereit.FdDup2(wFd, 1) ist der Standardweg um den Stdout eines Kindprozesses abzufangen (vor exec).O_CLOEXEC auf der Pipe verhindert, dass der fd nach exec() versehentlich geerbt wird.Enthaltene Untermodule im Überblick:
std.process — fork, exec, waitpidstd.mqueue — Message Queues (prioritätsbasiertes IPC)std.signals — Signal-basierte Prozesskommunikationstd.net.epoll — Pipe-fds lassen sich in epoll einbindenLetzte Aktualisierung: 2026-06-05