Como devo verificar se um determinado PID está sendo executado?

14

Estou escrevendo um script Perl que analisa arquivos de log para coletar PIDs e, em seguida, verifica se o PID está sendo executado. Estou tentando pensar na melhor maneira de fazer essa verificação. Obviamente, eu poderia fazer algo como:

system("ps $pid > /dev/null") && print "Not running\n";

No entanto, prefiro evitar a chamada do sistema, se possível. Eu, portanto, pensei que eu poderia usar o sistema de arquivos /proc (portabilidade não é uma preocupação, isso sempre estará rodando em um sistema Linux). Por exemplo:

if(! -d "/proc/$pid"){
    print "Not running\n";
}

Isso é seguro? Posso sempre supor que, se não houver um diretório /proc/$pid/ , o PID associado não está sendo executado? Espero que assim, já que o AFAIK ps obtém suas informações de /proc de qualquer maneira, mas como isso é para o código de produção, quero ter certeza.

Portanto, pode haver casos em que um processo em execução não tenha o diretório /proc/PID ou em que exista um diretório /proc/PID e o processo não esteja em execução? Existe alguma razão para preferir analisar ps sobre a verificação da existência do diretório?

    
por terdon 10.07.2016 / 19:35

2 respostas

18

A função perl kill(0,$pid) pode ser usada.

Se o código de retorno for 1, o PID existe e você pode enviar um sinal para ele.

Se o código de retorno for 0, então você precisa verificar $ !. Pode ser EPERM (permissão negada), o que significa que o processo existe ou ESRCH, caso em que o processo não existe.

Se o seu código de verificação estiver sendo executado como root , você poderá simplificar isso apenas para verificar o código de retorno de kill; 0 = > erro, 1 = > ok

Por exemplo:

% perl -d -e 0

Loading DB routines from perl5db.pl version 1.37
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(-e:1):   0
  DB<1> print kill(0,500)
0
  DB<2> print $!
No such process
  DB<3> print kill(0,1)
0
  DB<4> print $!
Operation not permitted
  DB<5> print kill(0,$$)
1

Isso pode ser feito em uma função simples

use Errno;

sub test_pid($)
{
  my ($pid)=@_;

  my $not_present=(!kill(0,$pid) && $! == Errno::ESRCH);

  return($not_present);
}

print "PID 500 not present\n" if test_pid(500);
print "PID 1 not present\n" if test_pid(1);
print "PID $$ not present\n" if test_pid($$);
    
por 10.07.2016 / 20:05
6
  • Tenho 99,9% de certeza de que verificar se existe /proc/PID (e é um diretório) é 98% tão confiável quanto a técnica kill 0 . A razão pela qual os 98% não são 100% é um ponto que Stephen Harris tocou (e ricocheteou) um comentário - ou seja, o sistema de arquivos /proc pode não ser montado. Pode ser válido afirmar que um sistema Linux sem /proc é um sistema danificado e degradado - afinal, coisas como ps , top e lsof provavelmente não funcionarão e isso pode não ser um problema para um sistema de produção. Mas é (teoricamente) possível que nunca tenha sido montado (embora isso possa impedir que o sistema chegue a um estado normal), é definitivamente possível que seja desmontado (Eu testei 1 ), e acredito que não há garantia de que existirá (isto é, não é exigido pelo POSIX). E, a menos que o sistema seja completamente fechado, kill funcionará.
  • O comentário de Stephen fala sobre "sair para o sistema de arquivos" e “usando chamadas do sistema nativo”. Eu acredito que isso é em grande parte um arenque vermelho.
    • Sim, qualquer tentativa de acessar /proc requer a leitura do diretório raiz para encontrar o sistema de arquivos /proc . Isto é verdade para qualquer tentativa de acessar qualquer arquivo por um nome de caminho absoluto, incluindo itens em /bin , /etc e /dev . Isso acontece com tanta frequência que o diretório raiz é seguramente armazenado em cache na memória por toda a vida útil (uptime) do sistema, então este passo pode ser feito sem qualquer E / S de disco. E, uma vez que você tenha o inode de /proc , tudo o mais que acontece está na memória.
    • Como você acessa /proc ? Com stat , open , readdir , etc. que são chamadas de sistemas nativas a cada bit, tanto quanto kill .
  • A questão fala sobre um processo em execução. Esta é uma frase escorregadia. Se você realmente quer testar se o processo está executando (isto é, na fila de execução; talvez o processo atual em alguma CPU; não dormindo, esperando ou parado), você pode precisar fazer um ps PID e ler a saída , ou olhe para /proc/PID/stat . Mas não vejo dica em sua pergunta ou comentários que você está preocupado com isso.

    O elefante na sala, no entanto, é um processo zumbi 2 pode ser difícil distinguir de um processo que está vivo e bem. kill 0 funciona em um zumbi e /proc/PID existe. Você pode identificar zumbis com as técnicas listadas no parágrafo anterior (fazendo ps PID e lendo a saída, ou olhando para /proc/PID/stat ). Meu muito rápido & testes casuais (isto é, não muito rigorosos) sugerem que você também pode fazer isso fazendo readlink ou lstat em /proc/PID/cwd , /proc/PID/root , ou /proc/PID/exe - estes falharão nos zumbis. (No entanto, eles também falharão nos processos que você não possui.)

por 14.07.2016 / 22:38