Come devo verificare se un determinato PID è in esecuzione?


16

Sto scrivendo uno script Perl che analizza i file di registro per raccogliere i PID e quindi controlla se quel PID è in esecuzione. Sto cercando di pensare al modo migliore per fare quel controllo. Ovviamente, potrei fare qualcosa del tipo:

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

Tuttavia, preferirei evitare la chiamata di sistema, se possibile. Ho quindi pensato di poter usare il /procfilesystem (la portabilità non è un problema, questo funzionerà sempre su un sistema Linux). Per esempio:

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

È sicuro? Posso sempre supporre che se non esiste una /proc/$pid/directory il PID associato non è in esecuzione? Mi aspetto così dal momento che AFAIK psstesso ottiene /proccomunque le sue informazioni, ma poiché questo è per il codice di produzione, voglio esserne sicuro.

Quindi, possono esserci casi in cui un processo in esecuzione non ha /proc/PIDdirectory o in cui /proc/PIDesiste una directory e il processo non è in esecuzione? C'è qualche motivo per preferire l'analisi psal controllo dell'esistenza della directory?


2
c'è anche la killfunzione perl che usa il segnale 0 che non uccide ma dice se puoi farlo (cioè hai bisogno dell'autorizzazione per segnalare quel processo).
Meuh

1
'/ proc / $ PID' dovrebbe andare bene se lo stai facendo in Linux.
likewhoa,

7
@terdon Nota che qualunque sia il metodo che usi (ed kill -0è il migliore), questo ti dice solo se c'è un processo in esecuzione con il PID dato . Non ti dice se il processo sarà ancora in esecuzione un millisecondo dopo, e non ti dice se il processo è quello a cui sei interessato o un processo non correlato a cui è stato assegnato lo stesso PID dopo l'interruzione del processo interessante . È quasi sempre un errore verificare se un determinato PID è in esecuzione : ci sono pochissime circostanze in cui questo non è soggetto a condizioni di gara.
Gilles 'SO- smetti di essere malvagio' il

1
@Gilles in effetti, dovrei anche controllare il nome del processo. Tuttavia, in questo caso, non mi importa se c'è un cambio di stato un millisecondo dopo. Ho i processi elencati come attivi in ​​dB e un file corrispondente con i pid. Devo solo verificare se qualcosa che il DB pensa sia in esecuzione non sia effettivamente in esecuzione e avere abbastanza controllo sulla configurazione per sapere che non può essere riavviato in modo casuale.
terdon

3
@MickLH wow, sono io a dirlo. In realtà sarebbe stato un commento utile invece di una celebrazione del tuo stesso splendore se ti fossi preso la briga di spiegare cosa è così brutto e pericoloso. Non dubito che tu abbia ragione, non ho mai affermato di essere un programmatore, motivo per cui ho posto la domanda, ma sei riuscito a essere sia offensivo che inutile.
Terdon

Risposte:


20

È kill(0,$pid)possibile utilizzare la funzione perl .

Se il codice di ritorno è 1, allora esiste il PID e ti è permesso inviargli un segnale.

Se il codice di ritorno è 0, è necessario controllare $ !. Potrebbe essere EPERM (autorizzazione negata) che significa che il processo esiste o ESRCH, nel qual caso il processo non esiste.

Se il tuo codice di controllo è in esecuzione come rootallora puoi semplificarlo semplicemente controllando il codice di ritorno di kill; 0 => errore, 1 => ok

Per esempio:

% 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

Questo può essere trasformato in una semplice funzione

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($$);

FWIW, ho aggiunto una semplice funzione che mostra come è possibile farlo.
Stephen Harris,

Sì, penso che ci andrò con questo. Ho cancellato il mio commento poiché mi sono reso conto che tutto ciò di cui avevo bisogno era if (!kill(0,$pid) && $! =~ /No such process/){ exit; }o simile. Mi piace Errnomeglio la tua soluzione, grazie. Mentre probabilmente andrò con questo, aspetterò un po 'nel caso in cui qualcuno possa rispondere alla domanda Linux sottostante.
terdon

2
Se /procè montato poi ogni PID visibile nello spazio dei nomi sarà presente, in modo che le -d /proc/$pidprova sarebbe lavorare ... ma si tratta di andare fuori per il filesystem invece di usare le chiamate di sistema nativi.
Stephen Harris,

È proprio quello che volevo evitare, sì.
terdon

2
@terdon: mi sono appena reso conto che la mia confusione derivava dal fatto che per "chiamata di sistema" intendevi in ​​realtà " systemchiamata", ovvero una chiamata alla systemfunzione stessa, non una "chiamata di sistema" . Quest'ultimo non puoi evitare, ma il primo certamente puoi farlo. Ha senso adesso!
user541686,

6
  • Sono sicuro al 99,9% che verificare se esiste (ed è una directory) è affidabile al 98% quanto la tecnica. Il motivo per cui il 98% non è del 100% è un punto su cui Stephen Harris ha toccato (e rimbalzato) in un commento - vale a dire, il filesystem potrebbe non essere montato. Può essere valida la rivendicazione che un sistema Linux senza è un danneggiato, sistema degradato - dopo tutto, le cose come , e probabilmente non funzionerà - e quindi questo potrebbe non essere un problema per un sistema di produzione. Ma è (teoricamente) possibile che non sia mai stato montato (anche se questo potrebbe impedire al sistema di raggiungere uno stato normale), è sicuramente possibile che sia smontato (l'ho testato 1/proc/PIDkill 0/proc/procpstoplsof) e credo che non vi sia alcuna garanzia che esista (ovvero, non è richiesto da POSIX). E, a meno che il sistema non sia completamente hosed, killfunzionerà.
  • Il commento di Stephen parla di "uscire al filesystem" e "usare chiamate di sistema native". Credo che si tratti in gran parte di un'aringa rossa.
    • Sì, qualsiasi tentativo di accesso /proc richiede la lettura della directory principale per trovare il /procfilesystem. Questo è vero per ogni tentativo di accedere a qualsiasi file un percorso assoluto, comprese le cose in /bin, /etce /dev. Ciò accade così spesso che la directory principale viene sicuramente memorizzata nella cache per l'intera durata (uptime) del sistema, quindi questo passaggio può essere eseguito senza alcun I / O su disco. E, una volta che hai l'inode /proc, tutto ciò che accade è in memoria.
    • Come si accede /proc? Con stat, open, readdir, ecc, che sono sistema nativo chiama ogni punta tanto quanto kill.
  • La domanda parla di un processo in corso. Questa è una frase scivolosa. Se si desidera effettivamente verificare se il processo è in esecuzione (ad esempio, nella coda di esecuzione; forse il processo corrente su una CPU; non inattivo, in attesa o arrestato), potrebbe essere necessario eseguire un e leggere l'output o guardare . Ma non vedo alcun suggerimento nella tua domanda o nei commenti che ti interessano.ps PID /proc/PID/stat

    L'elefante nella stanza, tuttavia, è che un processo di zombi 2 può essere difficile da distinguere da un processo che è vivo e vegeto.  kill 0lavora su uno zombi ed esiste. Puoi identificare gli zombi con le tecniche elencate nel paragrafo precedente (fare e leggere l'output o guardare ). Il mio molto rapido e casuale (cioè non molto approfondita) test suggerisce che si può anche fare questo facendo una o su , o - questi saranno fallire su zombie. (Tuttavia, falliranno anche sui processi che non possiedi.)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  se il -f( f opzione orza) non funziona, prova -l( l azy).
2  vale a dire, un processo che è uscito / è morto / terminato, ma il cui genitore non ha ancora eseguito a wait.


Grazie per il tuo commento sulla mia risposta, che ho eliminato perché era sbagliato. Non credo che la kill(2)manpage indichi direttamente il comportamento che hai indicato, ma la perlfuncmanpage lo fa. Manderò un'email a Michael Kerrisk per vedere cosa ha da dire sulla manpage del sistema.
jrw32982 supporta Monica il

Ho presentato una segnalazione di bug per chiarire la pagina di kill(2)
manuale

@ jrw32982: Bene, la pagina man dice cose come "L' argomento sig ... potrebbe essere 0, nel qual caso viene eseguito il controllo degli errori ..." e " ERRORI - La chiamata di sistema kill () fallirà e nessun segnale verrà inviato se: ... Il processo di invio non è il superutente e il suo ID utente effettivo non corrisponde all'ID utente effettivo del processo di ricezione. ... ”Ora che me lo dici, suppongo che possa essere interpretato in più di un modo, ma, purtroppo, molte pagine man di Unix sono scritte in questo stile, richiedendo che tu legga tra le righe. Michael può credere che sia abbastanza chiaro così com'è.
G-Man dice 'Reinstate Monica' il

Michael ha apportato una modifica alla kill(2)manpage (non la vedo ancora online): "Se sig è 0, non viene inviato alcun segnale, ma i controlli di esistenza e autorizzazione vengono comunque eseguiti; questo può essere utilizzato per verificare l'esistenza di un ID processo o ID gruppo processo che il chiamante è autorizzato a segnalare. "
jrw32982 supporta Monica il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.