Was sollten interaktive Shells in verwaisten Prozessgruppen tun?

10

(Erneutes Posten unter Unix gemäß dem Vorschlag in /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

Die kurze Frage ist, was sollte eine Shell tun, wenn sie sich in einer verwaisten Prozessgruppe befindet, der das tty nicht gehört? Aber ich empfehle, die lange Frage zu lesen, weil sie amüsant ist.

Hier ist eine unterhaltsame und aufregende Möglichkeit, Ihren Laptop mithilfe Ihrer Lieblingshülle in eine tragbare Raumheizung zu verwandeln (es sei denn, Sie sind einer dieser tcsh-Verrückten):

#include <unistd.h>   
int main(void) {
    if (fork() == 0) {
        execl("/bin/bash", "/bin/bash", NULL);
    }
    return 0;
}

Dies führt dazu, dass bash die CPU auf 100% fixiert. zsh und fish machen dasselbe, während ksh und tcsh etwas über Jobkontrolle murmeln und dann umkippen, was ein bisschen besser ist, aber nicht viel. Oh, und es ist ein plattformunabhängiger Straftäter: OS X und Linux sind beide betroffen.

Meine (möglicherweise falsche) Erklärung lautet wie folgt: Die untergeordnete Shell erkennt, dass sie nicht im Vordergrund steht : tcgetpgrp(0) != getpgrp(). Deshalb versucht es sich selbst zu stoppen : killpg(getpgrp(), SIGTTIN). Die Prozessgruppe ist jedoch verwaist, da die übergeordnete Gruppe (das C-Programm) der Anführer war und gestorben ist und SIGTTINan eine verwaiste Prozessgruppe gesendet wurde. Sie wird einfach gelöscht (andernfalls kann nichts erneut gestartet werden). Daher wird die untergeordnete Shell nicht gestoppt, sondern befindet sich immer noch im Hintergrund, sodass alles sofort wieder ausgeführt wird. Spülen und wiederholen.

Meine Frage ist, wie kann eine Befehlszeilen-Shell dieses Szenario erkennen und was ist das Richtige dafür? Ich habe zwei Lösungen, von denen keine ideal ist:

  1. Versuchen Sie, den Prozess zu signalisieren, dessen PID mit unserer Gruppen-ID übereinstimmt. Wenn dies fehlschlägt ESRCH, bedeutet dies, dass wir wahrscheinlich verwaist sind.
  2. Versuchen Sie einen nicht blockierenden Lesevorgang von einem Byte aus /dev/tty. Wenn dies fehlschlägt EIO, bedeutet dies, dass wir wahrscheinlich verwaist sind.

(Unser Problem, das dies verfolgt, ist https://github.com/fish-shell/fish-shell/issues/422 )

Danke für deine Gedanken!

lächerlich_fisch
quelle

Antworten:

4

Ich stimme Ihrer Analyse zu und ich stimme zu, dass Sie feststellen müssen, ob Ihre Prozessgruppe verwaist ist oder nicht.

tcsetattrsoll auch zurückkehren, EIOwenn die Prozessgruppe verwaist ist (und wir SIGTT OU nicht blockieren / ignorieren. Dies ist möglicherweise weniger aufdringlich als a readauf dem Terminal.

Beachten Sie, dass Sie es reproduzieren können mit:

(bash<&1 &)

Sie benötigen die Umleitung, andernfalls wird stdin nach / dev / null umgeleitet, wenn Sie einen Befehl im Hintergrund ausführen.

(bash<&1 & sleep 2)

Gibt noch seltsameres Verhalten, als wenn Sie am Ende zwei Muscheln vom Terminal lesen. Sie ignorieren SIGTTINund der neue erkennt nicht, sobald er gestartet wurde, dass er sich nicht mehr in der Vordergrundprozessgruppe befindet.

ksh93Die Lösung ist nicht so schlecht: Gehen Sie nur bis zu 20 Mal (statt unendlich) durch diese Schleife, bevor Sie aufgeben.

Stéphane Chazelas
quelle