¿Cómo debo verificar si se está ejecutando un PID determinado?

16

Estoy escribiendo un script de Perl que analiza los archivos de registro para recopilar PID y luego comprueba si ese PID se está ejecutando. Estoy tratando de pensar en la mejor manera de hacer esa verificación. Obviamente, podría hacer algo como:

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

Sin embargo, preferiría evitar la llamada al sistema si es posible. Por lo tanto, pensé que podría usar el /procsistema de archivos (la portabilidad no es una preocupación, esto siempre se ejecutará en un sistema Linux). Por ejemplo:

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

¿Eso es seguro? ¿Puedo suponer siempre que si no hay un /proc/$pid/directorio, el PID asociado no se está ejecutando? Lo espero ya que AFAIK psobtiene su información de /proctodos modos, pero como esto es para el código de producción, quiero estar seguro.

Entonces, ¿puede haber casos en que un proceso en ejecución no tenga un /proc/PIDdirectorio o donde /proc/PIDexista un directorio y el proceso no se esté ejecutando? ¿Hay alguna razón para preferir el análisis antes que psverificar la existencia del directorio?

terdon
fuente
2
también está la killfunción perl que usa la señal 0, que no mata pero dice si puede hacerlo (es decir, necesita permiso para señalar ese proceso).
meuh
1
'/ proc / $ PID' debería estar bien si está haciendo esto en Linux.
likewhoa
77
@terdon Tenga en cuenta que sea cual sea el método que utilice (y kill -0sea ​​el mejor), esto solo le indica si hay un proceso en ejecución con el PID dado . No le dice si el proceso seguirá ejecutándose un milisegundo más tarde, y no le dice si el proceso es el que le interesa o si es un proceso no relacionado al que se le asignó el mismo PID después de que el proceso interesante falleció. . Casi siempre es un error probar si se está ejecutando un PID dado : hay muy pocas circunstancias en las que esto no sea propenso a las condiciones de carrera.
Gilles 'SO- deja de ser malvado'
1
@Gilles de hecho, también debería verificar el nombre del proceso. Sin embargo, en este caso, no me importa si hay un cambio de estado un milisegundo más tarde. Tengo procesos listados como activos en un dB y un archivo correspondiente con los pids. Solo necesito verificar si algo que el DB cree que se está ejecutando en realidad no se está ejecutando y tener suficiente control sobre la configuración para saber que no puede iniciarse nuevamente al azar.
terdon
3
@MickLH wow, ese soy yo dicho. En realidad, eso habría sido un comentario útil en lugar de una celebración de tu propia brillantez si te hubieras molestado en explicar lo que es tan malo y peligroso. No dudo que tengas razón, nunca he pretendido ser un programador, por eso hice la pregunta, pero lograste ser insultante e inútil.
terdon

Respuestas:

20

Se kill(0,$pid)puede usar la función perl .

Si el código de retorno es 1, entonces existe el PID y se le permite enviarle una señal.

Si el código de retorno es 0, entonces debe verificar $ !. Puede ser EPERM (permiso denegado), lo que significa que el proceso existe o ESRCH, en cuyo caso el proceso no existe.

Si su código de comprobación se está ejecutando como rootentonces, puede simplificar esto simplemente comprobando el código de retorno de kill; 0 => error, 1 => ok

Por ejemplo:

% 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

Esto se puede convertir en una función simple

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($$);
Stephen Harris
fuente
FWIW, agregué una función simple que muestra cómo puedes hacer esto.
Stephen Harris
Sí, creo que iré con esto. Eliminé mi comentario porque me di cuenta de que todo lo que necesitaba era if (!kill(0,$pid) && $! =~ /No such process/){ exit; }o similar. Sin Errnoembargo, me gusta más tu solución, gracias. Si bien probablemente seguiré con esto, esperaré un tiempo en caso de que alguien pueda responder la pregunta subyacente de Linux.
terdon
2
Si /procse monta entonces cada PID visible en el espacio de nombres estará presente, por lo que su -d /proc/$pidprueba sería trabajar ... pero se trata de salir al sistema de archivos en lugar de utilizar las llamadas al sistema nativas.
Stephen Harris
Que es precisamente lo que quería evitar, sí.
terdon
2
@terdon: Acabo de darme cuenta de que mi confusión vino del hecho de que por "llamada al sistema" en realidad querías decir " systemllamada", es decir, una llamada a la systemfunción en sí, no una "llamada al sistema" . Lo último no se puede evitar, pero lo primero sí se puede. Tiene sentido ahora!
user541686
6
  • Estoy 99.9% seguro de que verificar si existe (y es un directorio) es 98% tan confiable como la técnica. La razón por la cual el 98% no es 100% es un punto que Stephen Harris mencionó (y rebotó) en un comentario , es decir, el sistema de archivos podría no estar montado. Puede que sea válida la reivindicación de que un sistema Linux sin es un sistema dañado degradado - después de todo, cosas como , y probablemente no funcionará - y por lo tanto esto podría no ser un problema para un sistema de producción. Pero es (teóricamente) posible que nunca se haya montado (aunque esto podría evitar que el sistema llegue a un estado normal), definitivamente es posible que se desmonte (lo he probado 1/proc/PIDkill 0/proc/procpstoplsof), y creo que no hay ninguna garantía de que exista (es decir, POSIX no lo requiere). Y, a menos que el sistema esté completamente conectado, killfuncionará.
  • El comentario de Stephen habla sobre "salir al sistema de archivos" y "usar llamadas al sistema nativo". Creo que esto es en gran medida un arenque rojo.
    • Sí, cualquier intento de acceso /proc requiere leer el directorio raíz para encontrar el /procsistema de archivos. Esto es cierto para cualquier intento de acceder a cualquier archivo por una ruta absoluta, incluyendo cosas en /bin, /etcy /dev. Esto sucede con tanta frecuencia que el directorio raíz seguramente se almacena en memoria caché durante toda la vida útil (tiempo de actividad) del sistema, por lo que este paso se puede realizar sin ninguna E / S de disco. Y, una vez que tiene el inodo de /proc, todo lo demás que sucede está en la memoria.
    • ¿Cómo se accede /proc? Con stat, open, readdir, etc, que son el sistema nativo llama exactamente igual que como kill.
  • La pregunta habla sobre un proceso en ejecución. Esta es una frase resbaladiza. Si realmente desea probar si el proceso se está ejecutando (es decir, en la cola de ejecución; tal vez el proceso actual en alguna CPU; sin dormir, esperando o detenido), es posible que deba hacer una lectura del resultado , o mirar . Pero no veo indicios en su pregunta o comentario de que esté preocupado por esto.ps PID /proc/PID/stat

    El elefante en la habitación, sin embargo, es que un proceso de zombie 2 puede ser difícil de distinguir de un proceso que está vivo y bien.  kill 0funciona en un zombi, y existe. Puede identificar zombies con las técnicas enumeradas en el párrafo anterior (hacer y leer el resultado, o mirar ). Mi prueba muy rápida y ocasional (es decir, no muy a fondo) sugiere que también se puede hacer esto haciendo una o en , o - estos fallarán en zombis. (Sin embargo, también fallarán en procesos que no son de su propiedad)./proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  si la opción -f( f orce) no funciona, intente -l( l azy).
2  es decir, un proceso que ha salido / muerto / terminado, pero cuyo padre aún no ha hecho a wait.

G-Man dice 'restablecer a Monica'
fuente
Gracias por tu comentario sobre mi respuesta, que he eliminado porque estaba equivocado. No creo que la página del kill(2)manual indique directamente el comportamiento que usted señaló, pero la página del perlfuncmanual sí. Enviaré un correo electrónico a Michael Kerrisk para ver qué tiene que decir sobre la página de manual del sistema.
jrw32982 apoya a Monica el
Presenté un informe de error para aclarar la página del manual kill(2)sobre los permisos para "enviar" la señal 0.
jrw32982 es compatible con Monica el
@ jrw32982: Bueno, la página del manual dice cosas como: "El argumento sig ... puede ser 0, en cuyo caso se realiza una comprobación de errores ..." y " ERRORES : la llamada al sistema kill () fallará y no se enviará ninguna señal si: ... El proceso de envío no es el superusuario y su identificación de usuario efectiva no coincide con la identificación de usuario efectiva del proceso de recepción. ... "Ahora que lo menciona, supongo que se puede interpretar de más de una manera, pero, lamentablemente, muchas páginas de manual de Unix están escritas en este estilo, lo que requiere que lea entre líneas. Michael puede creer que está lo suficientemente claro como es.
G-Man dice 'Restablecer a Monica' el
Michael realizó un cambio en la página de kill(2)manual (todavía no lo veo en línea): "Si sig es 0, entonces no se envía ninguna señal, pero aún se realizan verificaciones de existencia y permiso; esto puede usarse para verificar la existencia de un ID de proceso o ID de grupo de proceso que la persona que llama tiene permitido señalar ".
jrw32982 es compatible con Monica