Ausgabe von Pseudoterminal lesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

D'oh. Man sollte dem Schreibende der Pipe natürlich noch sagen, dass es bei einem `execv()` geschlossen werden sollte.

Code: Alles auswählen

from fcntl import fcntl, FD_CLOEXEC, F_GETFD, F_SETFD

# Das gleich nach ``parents_end, childs_end = os.pipe()``
fcntl(childs_end, F_SETFD, fcntl(childs_end, F_GETFD) | FD_CLOEXEC)
Jetzt sollte es aber funktionieren. Und das mit der Lesbarkeit überprüfen ist nicht heikel, das ist zum Scheitern verurteilt, IMHO.
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Das funktioniert jetzt. Verstehe ich das richtig:

- Erzeuge die Pipe und setze danach die Flags des Pipeendes `childs_end`, welches ja ein Filedescriptor ist, neu
- Verwende hierfür die bisherigen Flags + das neue Flag `FD_CLOEXEC`, welches den fd schliessen soll, wenn eine exec-Operation *erfolgreich* aufgerufen wurde
- Bei erfolgreichem `exec` wird also die Pipe geschlossen und hat nur einen leereren String im nun lesbaren Pipeende des Kindes
- Bei Misserfolg schreibt meine `os.read()`-Anweisung die Exception rein
- `os._exit()` würde dann das Kind schliessen und wird auch nur dann erreicht, wenn `os.execv()` abbrechen musste
- Jetzt schliesst der Elternprozess das Pipeende des Kindes: Warum eigentlich? Sollte das nicht besser im Block des Kindes kurz vor `os._exit()` stehen? Denn im Erfolgsfall hat man doch das Flag, das sich um's Schliessen kümmert. Außerdem könnte der Elternprozess dem Kind doch dann die Pipe vor der Nase zumachen, bevor dieses etwas reinschreiben kann, oder nicht?
- Danach wird jedenfalls geprüft, ob Daten da sind. Ich nehme an, `os.read()` wartet ab, bis ein leerer String kommt oder eben die Exception
- Wenn der String befüllt ist, wartet man auf noch die Beendigung des Kindes (das ja dann einen Fehler gehabt haben muss), weil man - so denke ich mal - sicher sein will, dass keine Daten mehr nachkommen und holt sich schließlich die Daten mit `pickle`.

Ich bohre deshalb so nach, weil ich den Ablauf meines Programms halt schon verstehen will. ;)
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Ich nehme an, du hast dich verschrieben und meintest natürlich `os.write()` anstatt `os.read()`.

Wichtig ist, dass du dir klar machst, was beim Fork passiert: Danach hast du zwei identische Prozesse. Das heißt, die haben auch dieselben Dateideskriptoren. Ergo hat deine Pipe vier Dateideskriptoren: Zwei zum Lesen (eine im Elternprozess, eine im Kindprozess), zwei zum Schreiben (dito). Dass die Prozesse also das Ende schließen, das sie nicht benutzen, hat also schon seine Richtigkeit.

Darauf zu warten, dass das Kind beendet ist, darauf kann wohl auch verzichtet werden. In eine Pipe kann eh nicht endlos geschrieben werden, wenn man nicht zwischendurch davon liest, also kann das in dem Fall hier sogar dazu führen, dass beide Prozesse niemals fortfahren (wenn die gepickelte Ausnahme größer als 1 MiB sein sollte). Auf jeden Fall sollte das lesbare Ende der Pipe im Elternprozess nach dem Lesen geschlossen werden, was ich in meinem Code leider vergessen habe (aus mehreren Gründen sollte das geschehen: damit keine Dateideskriptoren leaken und damit der Kindprozess nicht endlos hängt, weil er unter Umständen noch etwas in die Pipe schreiben mag, aber niemand mehr davon liest).
"Der Dumme erwartet viel. Der Denkende sagt wenig." ("Herr Keuner" -- Bertolt Brecht)
Antworten