Por que o navegador de cromo é interrompido quando fecho o terminal apesar do nohup?

12

Essa pergunta é antiga e ainda não estou claro sobre o porquê.


Pergunta original em 2014:

Na guia Terminal do Gnome, corri

$ nohup chromium-browser &

Mas quando fecho a aba terminal, chromium-browsertambém sai. Não nohupdeveria impedir isso? Gilles disse:

pode-se dizer que nohup e repudiar ambos suprimem SIGHUP, mas de maneiras diferentes. nohup faz o programa ignorar o sinal inicialmente (o programa pode mudar isso). o nohup também tenta providenciar para que o programa não tenha um terminal de controle, para que ele não seja enviado SIGHUP pelo kernel quando o terminal estiver fechado. a renúncia é puramente interna à concha; faz com que o shell não envie SIGHUP quando terminar.

Então nohup não faz o navegador de cromo ignorar o SIGHUP?

Também estou vendo isso em outros executáveis, como o Emacs (modo GUI). Mas não em xeyes.

Isso está acontecendo no Ubuntu 12.04, 32 bits, quando a pergunta foi publicada.


Atualização em 2015,

Agora estou executando o Ubuntu 14.04, em google-chromevez de chromium-browserinstalado. A mesma coisa que aconteceu com o chromium-browser antes também acontece com o google-chrome agora. nohup google-chrome 2>/dev/null &não impede que ele seja fechado quando a guia do terminal estiver fechada. /usr/bin/google-chromeé um link para um script bash /opt/google/chrome/google-chrome. Por que nohupo script aplicado ao bash não funciona? Como podemos fazê-lo funcionar em scripts bash? E os scripts Python?

Tim
fonte
1
Você deve contar mais sobre o seu ambiente. Não reproduzo seu caso de teste.
Jlliagre 17/10/2014
Com quais outros executáveis ​​você está vendo isso? Tente algo simples, por exemplo, como xeyes.
Warren Young
@WarrenYoung: Emacs (GUI). Mas xeyes funciona.
Tim

Respostas:

11

Quando você fecha uma janela do Terminal GNOME, um SIGHUP é enviado ao shell que estava sendo executado. O shell normalmente envia um SIGHUP para todos os grupos de processos que ele sabe que ele criou - mesmo os iniciados nohup- e depois sai. Se o shell for bash, ele ignorará o envio de um SIGHUP para qualquer grupo de processos com o qual o usuário tenha marcado disown.

A execução de um comando com nohupignora SIGHUP, mas o processo pode mudar isso. Quando a disposição do SIGHUP para um processo é o padrão, se ele receber um SIGHUP, o processo será encerrado.

O Linux fornece algumas ferramentas para examinar as configurações de sinal de um processo em execução.

O script de shell do navegador chromium faz um execdos aplicativos compilados, portanto seu ID do processo permanece o mesmo. Então, para ver suas configurações de sinal, corri nohup chromium-browser &e olhei /proc/$!/statuspara ver a disposição do sinal.

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

Esses são números hexadecimais. Isso mostra que o SIGHUP não é capturado e não é ignorado. Somente SIGPIPE (o 13º bit em SigIgn) é ignorado. Eu rastreei isso para o seguinte código :

// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
void SetupSignalHandlers() {
  // Sanitise our signal handling state. Signals that were ignored by our
  // parent will also be ignored by us. We also inherit our parent's sigmask.
  sigset_t empty_signal_set;
  CHECK(0 == sigemptyset(&empty_signal_set));
  CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));

  struct sigaction sigact;
  memset(&sigact, 0, sizeof(sigact));
  sigact.sa_handler = SIG_DFL;
  static const int signals_to_reset[] =
      {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
       SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP};  // SIGPIPE is set below.
  for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
    CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
  }

  // Always ignore SIGPIPE.  We check the return value of write().
  CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
}

Apesar do comentário, os sinais ignorados pelos pais não estão sendo ignorados. Um SIGHUP matará cromo.

A solução alternativa é fazer o que @ xx4h aponta: use o disowncomando no bash para que, se o bash precisar sair, ele não envie SIGHUP ao chromium-browsergrupo de processos. Você pode escrever uma função para fazer isso:

mychromium () { /usr/bin/chromium-browser & disown $!; }
Mark Plotnick
fonte
Obrigado. Agora eu entendo principalmente o que você quis dizer. "Como o script nunca redefiniu essa armadilha, o binário de cromo real é chamado com a disposição do SIGHUP definida como padrão". Ao "redefinir esta armadilha", você deseja alterar a armadilha do SIGHUP para a padrão, o que encerra o processo? Como você "redefine esta armadilha"?
Tim
Ah, ao "redefinir essa armadilha", eu quis dizer "definir a disposição desse sinal de volta ao que era antes do script de shell definir um manipulador para ele". Se o shell funcionasse trap "" 1, isso faria com que o shell (e seus filhos) ignorassem o SIGHUP. Eu vou esclarecer isso.
Mark Plotnick
Obrigado. Irá verificar após o seu esclarecimento. Agora estou tentando entender daemon, nohup, renúncia e histórico, então voltei para revisar minhas perguntas e respostas antigas que não entendi. As confusões sobre nohup, renúncia e plano de fundo são resolvidas principalmente, e eu estou preso ao conceito de daemon e como daemonizar um processo (veja abaixo). Agradeço novamente se você tiver tempo para ajudar novamente.
Tim
Eu olhei para o código do aplicativo chromium, e o código C ++ no aplicativo redefine o SIGHUP para o padrão incondicionalmente. Os trapcomandos no wrapper de script de shell não impedem isso e a execução nohupnão pode impedir isso. Vou revisar minha resposta para refletir isso.
Mark Plotnick
3

Se chromium-browserfor algo assim google-chrome, acho que o problema mais provável é que chromium-browser nãochromium é, mas é um invólucro de shell que inicializa o estado e então execs chromium.

Na minha google-chromeinstalação, o binário está realmente localizado /opt/google/chromee o wrapper in /usr/biné apenas um script de shell que configura muito ambiente a respeito de xdg-*padrões e caminhos absolutos e similares antes de se substituir pelo binário apropriado.

Nesse ponto, qualquer sinal que nohuppossa ter sido inicialmente ignorado em nome do script que ele chamou como filho deixará de importar e, a menos que o script do wrapper tenha o cuidado de organizá-lo de outra forma (o que não é), o ctty será herdado.

Tente file /usr/bin/chromium-browserverificar se é o shell-script que eu acho que é. Nesse caso, considere reescrevê-lo para melhor atender você.

Posso dizer que apenas o google-chrome 2>/dev/null &mantém aberto para mim, mas não me lembro se esse é um resultado provável das modificações que fiz no script - foi há mais de um ano.

mikeserv
fonte
Obrigado. A mesma coisa que aconteceu chromium-browserantes também acontece google-chromeagora. Eu não tenho chromium-browserinstalado. nohup google-chrome 2>/dev/null &não impede que ele seja fechado quando a guia do terminal estiver fechada. google-chromeé um script bash /opt/google/chrome/google-chrome. Por que o nohup aplicado a um script bash não funciona? Como podemos fazê-lo funcionar em scripts bash? E os scripts Python?
Tim
Bem, ele faz o trabalho no roteiro, mas o script é executado apenas por alguns nano-segundos antes de ser substituído pelo actual chromebinário.
precisa saber é o seguinte
você está dizendo no script que existe execo chromebinário atual ? Como modifico o script então? Aqui está o meu/opt/google/chrome/google-chrome
Tim
@ Tim - sim - veja o fundo? exec -a "$0" "$HERE/chrome" ... || exec -a "$0" "$HERE/chrome"... Na parte superior, $HEREé definido o valor de readlink $0 (qual é o seu caminho de instalação google-chrome), mas /opt/google/chrome/chromeé o binário - que é o que o script se substitui.
mikeserv
@ Tim: Na medida em que vai - você pode simplesmente largar o execprovavelmente. Você terminará com um pid extra (além de outros 1000) e um processo de espera, mas acho que essa é a extensão. Ou então você pode substituir execw / nohuptalvez. Tudo depende principalmente do que chromeserá tolerado - mas deve funcionar assim.
precisa saber é o seguinte