Как мне проверить, работает ли данный PID?

16

Я пишу Perl-скрипт, который анализирует лог-файлы для сбора PID, а затем проверяет, работает ли этот PID. Я пытаюсь придумать лучший способ сделать эту проверку. Очевидно, я мог бы сделать что-то вроде:

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

Однако я бы предпочел избегать системного вызова, если это возможно. Поэтому я подумал, что могу использовать /procфайловую систему (переносимость не имеет значения, она всегда будет работать в системе Linux). Например:

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

Это безопасно? Могу ли я всегда предполагать, что если нет /proc/$pid/каталога, связанный PID не работает? Я ожидаю, что так как AFAIK все равно psполучает информацию, /procно так как это для производственного кода, я хочу быть уверен.

Итак, могут ли быть случаи, когда запущенный процесс не имеет /proc/PIDкаталога или /proc/PIDкаталог существует, а процесс не запущен? Есть ли какая-либо причина, чтобы предпочесть разбор psпроверке существования каталога?

Тердон
источник
2
есть также killфункция perl, использующая сигнал 0, который не убивает, а говорит, что если вы можете это сделать (то есть вам нужно разрешение для сигнализации этого процесса).
meuh
1
'/ proc / $ PID' должно быть прекрасно, если вы делаете это в Linux.
likewhoa
7
@terdon Обратите внимание, что какой бы метод вы ни использовали (и kill -0он лучший), он только сообщает вам , есть ли запущенный процесс с данным PID . Он не сообщает вам, будет ли процесс по-прежнему выполняться через одну миллисекунду, и не сообщает вам, является ли этот процесс тем, который вас интересует, или не связанным процессом, который получил тот же PID после того, как интересный процесс умер , Почти всегда ошибочно проверять, работает ли данный PID : очень мало обстоятельств, когда это не подвержено условиям гонки.
Жиль "ТАК - перестань быть злым"
1
@ Жиль, действительно, я должен также проверить имя процесса. Однако в этом случае мне все равно, будет ли изменение статуса через миллисекунду. У меня есть процессы, перечисленные как активные в дБ и соответствующий файл с PID. Мне просто нужно проверить, работает ли что-то, что БД считает работающим, на самом деле, и иметь достаточный контроль над настройкой, чтобы знать, что она не может запуститься снова случайно.
Тердон
3
@ MickLH Ух ты, это я сказал. На самом деле это был бы полезный комментарий вместо празднования вашего собственного блеска, если бы вы удосужились объяснить, что же такого плохого и опасного. Я не сомневаюсь, что вы правы, я никогда не претендовал на то, чтобы быть программистом, поэтому я задал вопрос, но вам удалось быть оскорбительным и бесполезным.
Тердон

Ответы:

20

kill(0,$pid)Можно использовать функцию perl .

Если код возврата равен 1, тогда PID существует, и вы можете отправить ему сигнал.

Если код возврата равен 0, то вам нужно проверить $ !. Это может быть EPERM (отказано в разрешении), что означает, что процесс существует, или ESRCH, в этом случае процесс не существует.

Если ваш проверочный код работает как, rootто вы можете упростить это до простой проверки кода возврата kill; 0 => ошибка, 1 => хорошо

Например:

% 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

Это можно сделать простой функцией

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, я добавил простую функцию, показывающую, как вы можете это сделать.
Стивен Харрис
Да, я думаю, я пойду с этим. Я удалил свой комментарий, так как я понял, что все, что мне нужно, было if (!kill(0,$pid) && $! =~ /No such process/){ exit; }или похоже. Мне нравится ваше Errnoрешение, хотя, спасибо. Хотя я, вероятно, пойду с этим, подожду немного, если кто-нибудь сможет ответить на основной вопрос Linux.
Terdon
2
Если /procсмонтирован, то будет присутствовать каждый PID, видимый в пространстве имен, поэтому ваш -d /proc/$pidтест будет работать ... но он предполагает выход в файловую систему, а не с использованием системных системных вызовов.
Стивен Харрис
Да, именно этого я и хотел избежать.
Terdon
2
@terdon: Я только что понял, что моя путаница возникла из-за того, что под «системным вызовом» вы на самом деле подразумевали « systemвызов», то есть вызов самой systemфункции, а не «системный вызов» . Последнее вы не можете избежать, но первое вы, конечно, можете. Имеет смысл сейчас!
user541686
6
  • Я на 99,9% уверен, что проверка на наличие (и наличие каталога) на 98% надежнее, чем методика. Причина, по которой 98% - это не 100%, - это точка, которую Стивен Харрис затронул (и отскочил) в комментарии, а именно: файловая система может быть не смонтирована. Можно утверждать, что система Linux без поврежденной, деградировавшей системы - в конце концов, и тому подобное/proc/PIDkill 0/proc/procps , topи , lsofвероятно , не будет работать - и поэтому это может не быть проблемой для производственной системы. Но (теоретически) возможно, что он никогда не был смонтирован (хотя это может помешать системе перейти в нормальное состояние), вполне возможно, что он будет размонтирован (я проверял 1)), и я считаю, что нет никаких гарантий, что он будет существовать (то есть, это не требуется POSIX). И, если система полностью не подключена, killбудет работать.
  • Комментарий Стивена говорит о «выходе в файловую систему» ​​и «использовании системных вызовов». Я считаю, что это в основном красная сельдь.
    • Да, любая попытка доступа /proc требует чтения корневого каталога , чтобы найти в /procфайловой системе. Это верно для любой попытки получить доступ к любой файл, полное составное имя, в том числе вещей , в /bin, /etcи /dev. Это происходит так часто, что корневой каталог надежно кэшируется в памяти в течение всего времени жизни (времени безотказной работы) системы, поэтому этот шаг можно выполнить без дискового ввода-вывода. И, когда у вас есть инод /proc, все остальное, что происходит, находится в памяти.
    • Как вы получаете доступ /proc? С stat, open, readdirи т.д., которые являются родные системных вызовов каждый бит столько , сколько kill.
  • Вопрос говорит о запущенном процессе. Это скользкая фраза. Если вы действительно хотите проверить, запущен ли процесс (т. Е. В очереди выполнения; может быть, текущий процесс на каком-либо процессоре; не спит, не ждет или не остановлен), вам может потребоваться выполнить a и прочитать вывод или посмотреть на , Но я не вижу в вашем вопросе или комментариях намека на то, что вы обеспокоены этим.ps PID /proc/PID/stat

    Слон в комнате, однако, состоит в том, что процесс зомби 2 может быть трудно отличить от процесса, который жив и здоров.  kill 0работает на зомби и существует. Вы можете идентифицировать зомби с помощью методов, перечисленных в предыдущем параграфе (делать и читать вывод или смотреть на ). Мой очень быстро и случайным (то есть, не очень тщательно) тестирование предполагает , что вы можете сделать это делать или на , или - они будут терпеть неудачу на зомби. (Тем не менее, они также потерпят неудачу в процессах, которыми вы не владеете.)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1,  если опция -f( f orce) не работает, попробуйте -l( l azy).
2  т.е. процесс, который завершился / умер / завершился, но родитель которого еще не сделал a wait.

G-Man говорит: «Восстанови Монику»
источник
Спасибо за ваш комментарий к моему ответу, который я удалил, потому что он был неправильным. Я не верю, что kill(2)справочная страница прямо указывает на поведение, на которое вы указали, но perlfuncсправочная страница делает. Я отправлю электронное письмо Майклу Керриску, чтобы узнать, что он скажет о справочной странице системы.
jrw32982 поддерживает Монику
Я kill(2)отправил отчет об ошибке, чтобы уточнить страницу руководства, касающуюся разрешений на «отправку» сигнала 0.
jrw32982 поддерживает Monica
@ jrw32982: Ну, на странице руководства написано что-то вроде: « Аргумент sig … может быть 0, в этом случае проверка ошибок выполняется…» и « ОШИБКИ - системный вызов kill () не будет выполнен, и сигнал не будет отправлен, если: … Процесс отправки не является суперпользователем, и его эффективный идентификатор пользователя не совпадает с эффективным идентификатором пользователя процесса получения. … »Теперь, когда вы упомянули об этом, я полагаю, что это можно интерпретировать более чем одним способом, но, к сожалению, многие man-страницы Unix написаны в этом стиле, требуя от вас читать между строк. Майкл может поверить, что все достаточно ясно.
G-Man говорит: «Восстанови Монику»
Майкл внес изменения в kill(2)справочную страницу (я пока не вижу его в сети): «Если sig равен 0, то сигнал не отправляется, но проверки существования и разрешений по-прежнему выполняются; это можно использовать для проверки существования идентификатор процесса или идентификатор группы процессов, о которых разрешено сигнализировать вызывающей стороне. "
jrw32982 поддерживает Монику