Co powinny robić interaktywne powłoki w osieroconych grupach procesów?

10

(Ponowne publikowanie w unixie zgodnie z sugestią w /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

Krótkie pytanie brzmi: co powinna zrobić powłoka, jeśli znajduje się w osieroconej grupie procesów, która nie jest właścicielem tty? Ale polecam przeczytać długie pytanie, ponieważ jest zabawne.

Oto zabawny i ekscytujący sposób na przekształcenie laptopa w przenośny ogrzewacz pomieszczeń za pomocą ulubionej powłoki (chyba że jesteś jednym z tych dziwaków z tcsh):

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

To powoduje, że bash ustala procesor na 100%. Zsh i fish robią to samo, podczas gdy ksh i tcsh mamroczą coś o kontroli zadań, a następnie przewracają się, co jest nieco lepsze, ale niewiele. Aha, i jest to przestępca agnostyczny na platformę: dotyczy to zarówno systemu X, jak i Linux.

My (potencjalnie źle) wyjaśnienie jest następujące: powłoka dziecko wykryje to nie jest na pierwszym planie: tcgetpgrp(0) != getpgrp(). Dlatego stara się zatrzymać siebie: killpg(getpgrp(), SIGTTIN). Ale jego grupa procesów jest osierocona, ponieważ jej rodzic (program C) był liderem i zmarł, a SIGTTINwysłany do osieroconej grupy procesów jest po prostu odrzucany (w przeciwnym razie nic nie mogłoby go ponownie uruchomić). Dlatego skorupa potomna nie jest zatrzymywana, ale nadal znajduje się w tle, więc robi to wszystko od razu. Wypłukać i powtórzyć.

Moje pytanie brzmi: w jaki sposób powłoka wiersza poleceń może wykryć ten scenariusz i co należy zrobić? Mam dwa rozwiązania, z których żadne nie jest idealne:

  1. Spróbuj zasygnalizować proces, którego pid pasuje do naszego identyfikatora grupy. Jeśli to się nie powiedzie ESRCH, oznacza to, że prawdopodobnie jesteśmy osieroceni.
  2. Spróbuj nieblokującego odczytu jednego bajtu z /dev/tty. Jeśli to się nie powiedzie EIO, oznacza to, że prawdopodobnie jesteśmy osieroceni.

(Nasz problem ze śledzeniem tego to https://github.com/fish-shell/fish-shell/issues/422 )

Dzięki za twoje przemyślenia!

śmieszne ryby
źródło

Odpowiedzi:

4

Zgadzam się z twoją analizą i zgadzam się, że brzmi to tak, jakbyś musiał wykryć, czy twoja grupa procesów jest osierocona, czy nie.

tcsetattrma również zwrócić, EIOjeśli grupa procesów jest osierocona (a my nie blokujemy / ignorujemy SIGTT OU . Może to być mniej inwazyjny sposób niż readna terminalu.

Pamiętaj, że możesz go odtworzyć za pomocą:

(bash<&1 &)

Potrzebujesz przekierowania, w przeciwnym razie stdin zostanie przekierowane do / dev / null, gdy uruchomisz polecenie w tle.

(bash<&1 & sleep 2)

Daje nawet dziwniejsze zachowanie, ponieważ kończy się to na tym, że dwie powłoki odczytują z terminala. Ignorują SIGTTINi nowy nie wykrywa, gdy już się uruchomi, nie będzie już w grupie procesów pierwszego planu.

ksh93rozwiązanie nie jest takie złe: przejdź przez tę pętlę tylko 20 razy (zamiast nieskończonej), zanim się poddasz.

Stéphane Chazelas
źródło