Bagaimana saya harus memeriksa apakah PID yang diberikan sedang berjalan?

16

Saya sedang menulis skrip Perl yang mem-parsing file log untuk mengumpulkan PID dan kemudian memeriksa apakah PID itu berjalan. Saya mencoba memikirkan cara terbaik untuk melakukan pemeriksaan itu. Jelas, saya bisa melakukan sesuatu seperti:

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

Namun, saya lebih suka menghindari panggilan sistem jika memungkinkan. Karena itu saya pikir saya bisa menggunakan sistem /procfile (portabilitas bukan masalah, ini akan selalu berjalan pada sistem Linux). Sebagai contoh:

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

Apakah itu aman? Bisakah saya selalu berasumsi bahwa jika tidak ada /proc/$pid/direktori PID terkait tidak berjalan? Saya berharap demikian karena AFAIK pssendiri mendapatkan informasinya /proctetapi karena ini untuk kode produksi, saya ingin memastikan.

Jadi, dapatkah ada kasus di mana proses yang berjalan tidak memiliki /proc/PIDdirektori atau di mana /proc/PIDdirektori ada dan proses tersebut tidak berjalan? Apakah ada alasan untuk lebih memilih parsing psdaripada memeriksa keberadaan direktori?

terdon
sumber
2
ada juga killfungsi perl menggunakan sinyal 0 yang tidak membunuh tetapi mengatakan jika Anda bisa melakukannya (yaitu Anda perlu izin untuk memberi sinyal pada proses itu).
meuh
1
'/ proc / $ PID' seharusnya baik-baik saja jika Anda melakukan ini di Linux.
likewhoa
7
@terdon Perhatikan bahwa metode apa pun yang Anda gunakan (dan kill -0yang terbaik), ini hanya memberi tahu Anda apakah ada proses yang berjalan dengan PID yang diberikan . Itu tidak memberi tahu Anda apakah proses masih akan berjalan satu milidetik kemudian, dan tidak memberi tahu Anda apakah proses tersebut adalah yang Anda minati atau proses yang tidak terkait yang mendapat PID yang sama setelah proses yang menarik tersebut selesai . Hampir selalu merupakan kesalahan untuk menguji apakah suatu PID berjalan : ada sangat sedikit keadaan di mana ini tidak rentan terhadap kondisi balapan.
Gilles 'SO- stop being evil'
1
@Gilles memang, saya juga harus memeriksa nama proses. Namun, dalam hal ini, saya tidak peduli jika ada perubahan status milidetik nanti. Saya memiliki proses yang terdaftar sebagai aktif dalam dB dan file yang sesuai dengan pids. Saya hanya perlu memeriksa apakah sesuatu yang dianggap berjalan DB tidak benar-benar berjalan dan memiliki cukup kontrol atas pengaturan untuk mengetahui bahwa itu tidak dapat memulai lagi secara acak.
terdon
3
@MickLH wow, itu yang saya bilang. Itu sebenarnya akan menjadi komentar yang berguna, bukan perayaan kecemerlangan Anda sendiri seandainya Anda repot-repot menjelaskan apa yang begitu buruk dan berbahaya. Saya tidak ragu Anda benar, saya tidak pernah mengaku sebagai programmer, itulah sebabnya saya mengajukan pertanyaan, tetapi Anda berhasil menghina dan tidak membantu.
terdon

Jawaban:

20

Fungsi perl kill(0,$pid)dapat digunakan.

Jika kode pengembaliannya 1 maka PID ada dan Anda diizinkan mengirim sinyal kepadanya.

Jika kode pengembalian adalah 0 maka Anda perlu memeriksa $ !. Mungkin EPERM (izin ditolak) yang berarti proses itu ada atau ESRCH dalam hal mana proses itu tidak ada.

Jika kode pemeriksaan Anda berjalan rootmaka Anda dapat menyederhanakan ini hanya dengan memeriksa kode pengembalian kill; 0 => kesalahan, 1 => ok

Sebagai contoh:

% 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

Ini dapat dibuat menjadi fungsi sederhana

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
sumber
FWIW, saya menambahkan fungsi sederhana yang menunjukkan bagaimana Anda bisa melakukan ini.
Stephen Harris
Ya, saya pikir saya akan pergi dengan ini. Saya menghapus komentar saya karena saya menyadari bahwa yang saya butuhkan hanyalah if (!kill(0,$pid) && $! =~ /No such process/){ exit; }atau serupa. Saya suka Errnosolusi Anda lebih baik, terima kasih. Sementara saya mungkin akan pergi dengan ini, saya akan menunggu beberapa saat jika ada yang bisa menjawab pertanyaan Linux yang mendasarinya.
terdon
2
Jika /procsudah terpasang maka setiap PID yang terlihat di namespace akan ada, jadi -d /proc/$pidpengujian Anda akan berhasil ... tetapi melibatkan keluar ke sistem file daripada menggunakan panggilan sistem asli.
Stephen Harris
Justru itulah yang ingin saya hindari, ya.
terdon
2
@terdon: Saya baru menyadari kebingungan saya berasal dari fakta bahwa dengan "panggilan sistem" Anda sebenarnya berarti " systempanggilan" - yaitu, panggilan ke systemfungsi itu sendiri, bukan "panggilan sistem" . Yang terakhir Anda tidak bisa menghindari, tetapi yang pertama Anda pasti bisa. Masuk akal sekarang!
user541686
6
  • Saya 99,9% yakin bahwa memeriksa apakah ada (dan merupakan direktori) 98% dapat diandalkan seperti teknik. Alasan mengapa 98% tidak 100% adalah titik yang disentuh Stephen Harris (dan terpental) dalam komentar - yaitu, sistem file mungkin tidak dipasang. Ini mungkin berlaku untuk klaim bahwa sistem Linux tanpa adalah rusak, sistem terdegradasi - setelah semua, hal seperti , , dan mungkin tidak akan bekerja - dan jadi kekuatan ini tidak menjadi masalah untuk sistem produksi. Tapi itu (secara teoritis) mungkin untuk itu tidak pernah dipasang (walaupun ini mungkin mencegah sistem dari datang ke keadaan normal), itu pasti mungkin untuk tidak di-mount (saya sudah mengujinya 1/proc/PIDkill 0/proc/procpstoplsof), dan saya percaya bahwa tidak ada jaminan bahwa itu akan ada (yaitu, itu tidak diperlukan oleh POSIX). Dan, kecuali sistem itu sepenuhnya disemprot, killakan berfungsi.
  • Komentar Stephen berbicara tentang "pergi ke sistem file" dan "menggunakan panggilan sistem asli". Saya percaya bahwa ini sebagian besar adalah herring merah.
    • Ya, setiap upaya untuk mengakses /proc memerlukan membaca direktori root untuk menemukan sistem /procfile. Hal ini berlaku untuk setiap usaha untuk mengakses setiap file dengan nama path absolut, termasuk hal-hal di /bin, /etc, dan /dev. Ini terjadi begitu sering sehingga direktori root pasti di-cache dalam memori untuk seumur hidup (uptime) sistem, sehingga langkah ini dapat dilakukan tanpa disk I / O. Dan, begitu Anda memiliki inode /proc, semua hal lain yang terjadi adalah dalam memori.
    • Bagaimana Anda mengakses /proc? Dengan stat, open, readdir, dll, yang sistem asli panggilan setiap bit sebanyak kill.
  • Pertanyaannya berbicara tentang proses yang sedang berjalan. Ini adalah ungkapan yang licin. Jika Anda benar-benar ingin menguji apakah proses sedang berjalan (yaitu, dalam antrian proses; mungkin proses saat ini pada beberapa CPU; tidak tidur, menunggu, atau berhenti), Anda mungkin perlu melakukan dan membaca output , atau melihat . Tetapi saya tidak melihat petunjuk dalam pertanyaan atau komentar Anda bahwa Anda prihatin dengan ini.ps PID /proc/PID/stat

    Gajah di ruangan itu, bagaimanapun, adalah bahwa proses zombie 2 bisa sulit dibedakan dari proses yang hidup dan sehat.  kill 0bekerja pada zombie, dan ada. Anda dapat mengidentifikasi zombie dengan teknik yang tercantum dalam paragraf sebelumnya (melakukan dan membaca hasilnya, atau melihat ). Saya sangat cepat & santai (yaitu, tidak sangat teliti) pengujian menunjukkan bahwa Anda juga dapat melakukan ini dengan melakukan atau pada , atau - ini akan gagal pada zombie. (Namun, mereka juga akan gagal pada proses yang tidak Anda miliki.)/proc/PIDps PID/proc/PID/statreadlinklstat/proc/PID/cwd/proc/PID/root/proc/PID/exe

____________
1  jika opsi -f( f ) tidak berfungsi, coba -l( l azy).
2  yaitu, proses yang telah keluar / mati / diakhiri, tetapi orang tuanya belum melakukan a wait.

G-Man Mengatakan 'Reinstate Monica'
sumber
Terima kasih atas komentar Anda pada jawaban saya, yang telah saya hapus karena salah. Saya tidak percaya halaman kill(2)manual menunjukkan secara langsung perilaku yang Anda tunjukkan, tetapi halaman perlfuncmanualnya menunjukkan. Saya akan mengirim email ke Michael Kerrisk untuk mengetahui apa yang dia katakan tentang halaman sistem.
jrw32982 mendukung Monica
Saya mengajukan laporan bug untuk mengklarifikasi halaman manual untuk kill(2)perijinan tentang "mengirim" sinyal 0.
jrw32982 mendukung Monica
@ jrw32982: Nah, halaman manual mengatakan hal-hal seperti, " Argumen sig ... mungkin 0, di mana pengecekan error dilakukan ..." dan " KESALAHAN - Panggilan sistem kill () akan gagal dan tidak ada sinyal yang akan dikirim jika: ... Proses pengiriman bukan pengguna super dan id pengguna efektifnya tidak cocok dengan id pengguna efektif dari proses penerimaan. … ”Sekarang setelah Anda menyebutkannya, saya kira itu dapat ditafsirkan dalam lebih dari satu cara, tetapi, sayangnya, banyak halaman manual Unix ditulis dengan gaya ini, mengharuskan Anda untuk membaca yang tersirat. Michael mungkin percaya bahwa itu sudah cukup jelas.
G-Man Mengatakan 'Reinstate Monica'
Michael membuat perubahan ke halaman kill(2)manual (saya belum melihatnya online): "Jika sig adalah 0, maka tidak ada sinyal yang dikirim, tetapi pemeriksaan keberadaan dan izin masih dilakukan; ini dapat digunakan untuk memeriksa keberadaan suatu ID proses atau ID grup proses yang diizinkan oleh penelepon untuk memberi sinyal. "
jrw32982 mendukung Monica