Como matar todos os processos filhos de um terminal, não uma sessão tty?

1

No meu local de trabalho, temos um cluster de computação de alto desempenho gerenciado pelo SLURM.

O trabalho de algumas pessoas gera muitos processos com, como federação, um único trabalho. Eles também escrevem mal o controlador de nível superior, então o SIGINT faz com que os processos filhos se tornem zumbis.

Devido à natureza desse ambiente, não é razoável (por nenhuma razão realmente válida) esperar que eles corrijam isso.

Então, estou tentando criar um wrapper de envio que, no final do trabalho, elimine todos os processos filhos.

Por padrão,

ps agarra todos os processos associados à sessão tty atual. No entanto, SLURM faz coisas estúpidas e ps não é apenas os processos para esta tarefa deste trabalho, mas também outras tarefas, assim elimina tudo em um nó físico sempre que um trabalho morre.

Então, como obtenho / mato todos os trabalhos que são filhos do script bash atual ?

    
por iAdjunct 07.06.2016 / 17:08

1 resposta

1

O processo atual (o processo de scripts ou shells, qualquer que seja o caso) é armazenado em $$ Usando esse PID, você pode usar o comando pgrep com o sinalizador -P: pgrep -P $$
para obter uma lista de todos os PIDs com o PID pai de $$

Aqui está um script de prova de conceito super simples:

#!/bin/bash

curpid="$$"
#launch 2 useless child processes
cat /dev/random > /dev/null &
cat /dev/random > /dev/null &
cpid='pgrep -P $curpid'  && echo "$(basename $0) pid: $curpid; child pids:" $cpid
#kill the child pids
kill $cpid
# check if any child pids still exist
newcpid='pgrep -P $curpid'
if [ $? -ne "0" ] || [ "$newcpid" != "" ]; then
  echo "no child pids left..."
else
  echo $newcpid
fi

Saída:

{0} 02:34:57] $ ./test3.sh 
test3.sh pid: 7015; child pids: 7016 7017
./test3.sh: line 12:  7016 Terminated              cat /dev/random > /dev/null
./test3.sh: line 12:  7017 Terminated              cat /dev/random > /dev/null
no child pids left...

Se você iniciar qualquer processo filho como outro usuário (por exemplo, sudo), talvez não tenha permissão para matar o processo, mesmo sendo pai / mãe. Se você mudar um dos

cat /dev/random > /dev/null &

linhas para

sudo cat /dev/random > /dev/null &

você não poderá matar esse processo (supondo que você tenha iniciado o script inicialmente com uma conta de usuário comum)

Script modificado (executando um filho como raiz e gerando informações de diferenças no final):

#!/bin/bash

curpid="$$"
#launch 2 useless child processes
cat /dev/random > /dev/null &
sudo cat /dev/random > /dev/null &
cpid='pgrep -P $curpid'  && echo "$(basename $0) pid: $curpid; child pids:" $cpid
#kill the child pids
kill $cpid
sleep 0.5
#check on children
for i in $cpid; do
  echo -n "PID: $i; Orig PPID: $curpid; Cur PPID: "'/usr/bin/ps --ppid $i | grep -Eo '[0-9]{3,}''
  echo
done

Saída com um dos filhos executando como root:

[{0} 02:53:51] $ ./test3.sh 
test3.sh pid: 8144; child pids: 8145 8146
./test3.sh: line 9: kill: (8146) - Operation not permitted
./test3.sh: line 10:  8145 Terminated              cat /dev/random > /dev/null
PID: 8145; Orig PPID: 8144; Cur PPID: 
PID: 8146; Orig PPID: 8144; Cur PPID: 8150

O PID filho lançado que foi iniciado como raiz não considera mais o script inicial como pai, em vez disso, é o subshell criado com a chamada sudo. A saída de ps auxf
mostra isso claramente também:

root      8146  0.0  0.0 244996  7444 pts/2    S    02:54   0:00 sudo cat /dev/random
root      8150  0.0  0.0 113828   744 pts/2    S    02:54   0:00  \_ cat /dev/random

Esse problema não é o ponto crucial da sua pergunta, mas é algo que você deve ter em mente.

    
por 09.06.2016 / 08:33