Pergunta

Eu tenho alguns processos aparecendo como <defunct> dentro top (e ps). Eu fervei as coisas dos scripts e programas reais.

No meu crontab:

* * * * * /tmp/launcher.sh /tmp/tester.sh

O conteúdo de launcher.sh (que é claro que é executável marcado):

#!/bin/bash
# the real script does a little argument processing here
"$@"

O conteúdo de tester.sh (que é claro que é executável marcado):

#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background

ps mostra o seguinte:

user       24257 24256  0 18:32 ?        00:00:00 [launcher.sh] <defunct>
user       24259     1  0 18:32 ?        00:00:00 sleep 27

Observe que tester.sh Não aparece-saiu após o lançamento do trabalho em segundo plano.

Porque launcher.sh Fique por perto, marcado <defunct>? Parece apenas fazer isso quando lançado por cron-Não quando eu mesmo corro.

Nota adicional: launcher.sh é um script comum no sistema em que isso é executado, que não é facilmente modificado. As outras coisas (crontab, tester.sh, até o programa que eu corro em vez de sleep) pode ser modiificado com muito mais facilidade.

Foi útil?

Solução

Porque eles não foram objeto de um wait(2) Chamada do sistema.

Como alguém pode esperar por esses processos no futuro, o kernel não pode se livrar completamente deles ou não será capaz de executar o wait Chamada do sistema porque não terá mais o status de saída ou evidência de sua existência.

Quando você inicia um da concha, seu shell está prendendo o Sigchld e fazendo várias operações de espera de qualquer maneira, então nada permanece extinto por muito tempo.

Mas Cron não está em um estado de espera, está dormindo, então a criança extinta pode ficar por um tempo até que Cron acorde.


Atualizar: Respondendo ao comentário ... hmm. Eu consegui duplicar o problema:

 PPID   PID  PGID  SESS COMMAND
    1  3562  3562  3562 cron
 3562  1629  3562  3562  \_ cron
 1629  1636  1636  1636      \_ sh <defunct>
    1  1639  1636  1636 sleep

Então, o que aconteceu foi, eu acho:

  • Cron Forks e Cron Child inicia a concha
  • Shell (1636) inicia Sid e PGID 1636 e começa a dormir
  • Shell sai, Sigchld enviado para Cron 3562
  • o sinal é ignorado ou maltratado
  • Shell se vira zumbi. Observe que o sono é reparado em iniciar, portanto, quando o sono sai, o Init receberá o sinal e a limpeza. Ainda estou tentando descobrir quando o zumbi é colhido. Provavelmente, sem crianças ativas, o Cron 1629 descobre que pode sair, nesse ponto o zumbi será reparado em iniciar e ser colhido. Então agora nos perguntamos sobre o Sigchld desaparecido que Cron deveria ter processado.
    • Não é necessariamente culpa de Vixie Cron. Como você pode ver aqui, Libdaememon instala um manipulador de Sigchld durante daemon_fork(), e isso pode interferir na entrega de sinal em uma saída rápida pelo intermediário 1629

      Agora, eu nem sei se Vixie Cron no meu sistema Ubuntu é construído com libdaemon, mas pelo menos eu tenho uma nova teoria. :-)

Outras dicas

Suspeito que Cron esteja aguardando todos os subprocessos da sessão para terminar. Veja Wait (2) em relação a argumentos negativos da PID. Você pode ver a sess com:

ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm

Aqui está o que vejo (editado):

STAT  EUID  RUID TT       TPGID  SESS  PGRP  PPID   PID %CPU COMMAND
Ss       0     0 ?           -1  3197  3197     1  3197  0.0 cron
S        0     0 ?           -1  3197  3197  3197 18825  0.0  \_ cron
Zs    1000  1000 ?           -1 18832 18832 18825 18832  0.0      \_ sh <defunct>
S     1000  1000 ?           -1 18832 18832     1 18836  0.0 sleep

Observe que o SH e o sono estão na mesma sess.

Use o comando Setsid (1). Aqui está tester.sh:

#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background

Observe que você não precisa &, Setsid o coloca em segundo plano.

Na minha opinião, isso é causado pelo processo Crond (gerado por Crond para todas as tarefas) aguardando a contribuição no stdin, que é canalizada para o stdout/stderr do comando no crontab. Isso é feito porque o Cron é capaz de enviar a saída resultante por correio para o usuário.

Portanto, Crond está esperando o EOF até o comando do usuário e tudo o que seus processos infantis gerados fecharam o tubo. Se isso for feito, Crond continuar com a estatura de espera e, em seguida, o comando do usuário extinto desaparece.

Então, acho que você precisa desconectar explicitamente todos os subprocessos gerados no seu script do tubo (por exemplo, redirecionando -o para um arquivo ou /dev /null.

Portanto, a linha a seguir deve funcionar em Crontab:

* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & ) 

Eu recomendo que você resolva o problema simplesmente não tendo dois processos separados: tenha launcher.sh Faça isso em sua última linha:

exec "$@"

Isso eliminará o processo supérfluo.

Encontrei essa pergunta enquanto procurava uma solução com um problema semelhante. Infelizmente, as respostas nesta pergunta não resolveram meu problema.

Matar o processo extinto não é uma opção, pois você precisa encontrar e matar seu processo pai. Acabei matando os processos extintos da seguinte maneira:

ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh

Em "Grep" ", você pode restringir a pesquisa a um processo extinto específico que procura.

Eu testei o mesmo problema tantas vezes. E finalmente eu tenho a solução. Basta especificar o '/bin/bash' antes do script bash, como mostrado abaixo.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top