O que os shells interativos devem fazer em grupos de processos órfãos?

10

(Postando novamente em unix, de acordo com a sugestão em /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

A pergunta curta é: o que um shell deve fazer se estiver em um grupo de processos órfãos que não possui o tty? Mas recomendo a leitura da longa pergunta porque é divertida.

Aqui está uma maneira divertida e emocionante de transformar seu laptop em um aquecedor de ambiente portátil, usando seu shell favorito (a menos que você seja um desses esquisitos do tcsh):

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

Isso faz com que o bash atrele a CPU a 100%. O zsh e o fish fazem o mesmo, enquanto o ksh e o tcsh murmuram algo sobre o controle do trabalho e depois caem, o que é um pouco melhor, mas não muito. Ah, e é um infrator independente de plataforma: OS X e Linux são afetados.

Meu (potencialmente errado) explicação é a seguinte: o shell criança detecta que não está em primeiro plano: tcgetpgrp(0) != getpgrp(). Por isso, tenta impedi-se: killpg(getpgrp(), SIGTTIN). Mas seu grupo de processos é órfão, porque seu pai (o programa C) foi o líder e morreu, e SIGTTINenviado para um grupo de processos órfão é descartado (caso contrário, nada poderia iniciá-lo novamente). Portanto, o shell filho não é parado, mas ainda está em segundo plano, e faz tudo de novo imediatamente. Enxague e repita.

Minha pergunta é: como um shell de linha de comando pode detectar esse cenário e qual é a coisa certa a fazer? Eu tenho duas soluções, nenhuma das quais é ideal:

  1. Tente sinalizar o processo cujo pid corresponde ao nosso ID de grupo. Se isso falhar ESRCH, significa que provavelmente somos órfãos.
  2. Tente uma leitura sem bloqueio de um byte /dev/tty. Se isso falhar EIO, significa que provavelmente somos órfãos.

(Nosso problema de rastreamento é https://github.com/fish-shell/fish-shell/issues/422 )

Obrigado por seus pensamentos!

ridiculous_fish
fonte

Respostas:

4

Concordo com sua análise e parece que você precisa detectar se seu grupo de processos é órfão ou não.

tcsetattrtambém deve retornar EIOse o grupo de processos for órfão (e não estivermos bloqueando / ignorando a UO SIGTT . Isso pode ser uma maneira menos invasiva do que uma readno terminal.

Observe que você pode reproduzi-lo com:

(bash<&1 &)

Você precisa do redirecionamento, caso contrário, o stdin será redirecionado para / dev / null ao executar um comando em segundo plano.

(bash<&1 & sleep 2)

Dá um comportamento ainda mais estranho, como se você tivesse duas conchas lendo no terminal. Eles estão ignorando SIGTTINe o novo não está detectando, uma vez iniciado, ele não está mais no grupo de processos em primeiro plano.

ksh93A solução não é tão ruim: apenas suba 20 vezes (em vez de infinito) através desse loop antes de desistir.

Stéphane Chazelas
fonte