Teste se um processo deixou algum órfão para trás

1

Eu não preciso esperar por eles, só preciso de um sim ou não.

Eu estou executando um programa que eu sei que vai bifurcar (e as crianças provavelmente vão bifurcar também). Se executado corretamente, deve cuidar de todos os seus filhos e sair deles quando terminar. Eu preciso escrever um teste que verifique se isso é verdade. Processos órfãos são atribuídos ao processo init, então não posso mais vê-los no pstree.

Pontos de bônus se eu puder obter uma lista de seus PIDs para que eu possa enviar SIGKILL para eles. Idealmente, se é algo POSIX-y, então funcionaria no * BSD.

    
por M.K. 16.05.2016 / 10:31

2 respostas

1

Quando um processo termina, o PPID de seus filhos é definido como 1 (adoção pelo init), mas o PGID (identificador do grupo de processos) e o SID (identificador de sessão) não mudam.

Os filhos do processo provavelmente não alteram seu grupo de processos, a menos que sejam destinados a serem daemons. Supondo que não, inicie o processo a ser testado em seu próprio grupo de processos. Chame setpgid(getpid(), getpid()) de sua estrutura de teste, depois de bifurcar e antes de chamar execve para executar o programa que está sendo testado. Chame kill(-test_program_pid, 0) ( kill com um argumento pid negativo e o valor do sinal 0) para testar se existe um processo em execução com o PGID test_program_pid . Passe SIGKILL como o argumento de sinal para matar todos eles.

test_program_pid = fork();
if (test_program_pid) {
    waitpid(test_program_pid, &status, 0);
    if (kill(-test_program_pid, 0)) {
        record_failue("some child processes were not terminated properly");
    }
    kill(-test_program_pid, SIGKILL);
} else {
    setpgid(getpid(), getpid());
    execve("/program/to/test", …);
}

Um método alternativo seria criar um arquivo temporário e abri-lo no programa que você está testando e em nenhum outro lugar. Se o programa chamar execve , verifique se o descritor de arquivo está aberto sem o sinalizador O_CLOEXEC (ou chame fcntl(fd, FD_CLOEXEC, 0) ). Esse método pressupõe que o programa não vá e feche os descritores de arquivo que ele não usa explicitamente. Você pode então executar fuser /temp/file para listar os processos que possuem este arquivo aberto e fuser -k /temp/file para eliminá-los. Uma variante dessa abordagem que funciona mesmo com programas que fecham descritores de arquivos que eles não usam, mas presumem que o programa não altera seu diretório atual, é criar um diretório temporário e mudar para esse diretório para executar o programa. / p>     

por 17.05.2016 / 01:45
2

Uma maneira de encontrá-los seria usar ps -ef , procurando linhas nas quais o pai-id é "1", por exemplo,

#!/bin/sh
orphans="$(ps -ef | awk '$3 == 1{ print $2; }')"
echo "Processes which might be orphans: $orphans"

No entanto, muitos processos têm "1" como pai. Determinar quais são interessantes para você pode ser feito lembrando quais processos filhos seu programa criou.

Se você conhece o nome de login (e / ou user-id ) sob o qual esses processos são criados, você pode eliminar algumas das possibilidades. A primeira coluna de ps pode mostrar (dependendo do tipo de sistema) o login name ou o user-id correspondente . POSIX oferece alguma ajuda aqui, mas é fácil encontrar sistemas que diferem - e a documentação reflete isso :

  • O FreeBSD 10, por exemplo, não mostra o nome de login para a opção -f . Com apenas ps -ef , mostra o id do processo na primeira coluna e não mostra o ID do processo do pai. Isso requer que a opção -l mostre (em vez disso) o user-id .
  • O OSX fornece o ID do usuário em ambos os casos ( ps -ef ou ps -efl ).
  • Dada a opção -l , o Solaris 10 mostra sinalizadores de processo na primeira e segunda colunas. Isso é mencionado no POSIX, embora o conteúdo dos flags não seja especificado (porque o conteúdo difere entre as plataformas Unix ).
  • O Linux fornece o nome de login e os sinalizadores de processo conforme o POSIX.

Como você pode ver, para alguns subconjuntos dos sistemas disponíveis, ps -efl daria o "mesmo" resultado para as três primeiras colunas. Para algo mais geral, você teria que olhar para o cabeçalho (primeira linha) e determinar qual coluna contém as informações correspondentes ao proprietário do processo ( login name ou user-id ) e o id do processo e o ID do processo do pai dele .

Para um determinado sistema (conhecendo as opções utilizáveis para ps e sabendo se corresponde ao nome de logon ou user-id ), você pode usar awk para corresponder a esse campo também, por exemplo,

#!/bin/sh
orphans="$(ps -ef | awk -v user=$LOGNAME '($1 == user && $3 == 1){ print $2; }')"
echo "Processes which might be orphans: $orphans"

Aqui eu usei $LOGNAME , para explicar o uso do POSIX pelo termo nome de login , o que poderia ser enganoso (já que em princípio os processos poderiam ser via sudo , enquanto o POSIX usava o termo implica que eles vieram através de um "login").

Leitura adicional:

por 16.05.2016 / 10:54

Tags