Sinyal

Mengirim sinyal dengan kill: SIGTERM versus SIGKILL dan kapan kill -9 dipakai.

Daftar isi

Topik ini membahas sinyal sebagai mekanisme kernel untuk memberi tahu proses bahwa sesuatu perlu ditangani, dengan kill sebagai perintah pengirimnya dari shell. Fokusnya ada pada dua sinyal yang paling sering dipakai untuk menghentikan proses, yaitu SIGTERM yang memberi kesempatan berhenti dengan rapi dan SIGKILL yang bekerja tanpa peringatan. Setelah membacanya, pemilihan antara kill, kill -9, dan sinyal lain menjadi keputusan yang sadar, bukan kebiasaan mengetik yang sama untuk semua keadaan.

Sinyal sebagai pesan kernel#

Sinyal (signal) adalah pemberitahuan pendek yang dikirim kernel atau proses lain kepada sebuah proses. Isinya hanya nomor dan nama, misalnya “sinyal 15 datang”, tanpa data tambahan. Setiap proses menentukan sikapnya sendiri terhadap sinyal yang diterima: menangkapnya dengan penangan khusus, mengabaikannya, atau membiarkan perilaku bawaannya berjalan. Untuk banyak sinyal, perilaku bawaan itu berarti proses berhenti. Perintah kill mengirim sinyal dari shell, dan padanannya di banyak bahasa pemrograman disebut dengan nama yang sama.

Setiap sinyal memiliki nomor yang tetap, dan kill -l menerjemahkan dua arah antara nama dan nomornya.

bash
mkdir -p /tmp/kerja-sinyal
cd /tmp/kerja-sinyal
# kill -l menerjemahkan nama dan nomor sinyal dua arah
kill -l TERM
kill -l KILL
kill -l 9
kill -l 15
text Keluaran
15
9
KILL
TERM
SinyalNomorPeran yang lazim
SIGHUP1Putusnya sesi terminal, juga dipakai sebagai permintaan memuat ulang konfigurasi
SIGINT2Tekanan Ctrl-C pada proses latar depan
SIGKILL9Penghentian paksa yang tidak dapat ditolak
SIGTERM15Permintaan berhenti yang sopan, bawaan dari kill
SIGSTOP dan SIGCONT19 dan 18Menahan dan melanjutkan proses

Nomor 9 dan 15 layak dihafal karena keduanya menjadi pilihan sehari-hari, sedangkan sinyal-sinyal lain dicari melalui kill -l ketika diperlukan.

kill dan SIGTERM#

Perintah kill tanpa opsi mengirim SIGTERM, yaitu permintaan berhenti yang diharapkan ditanggapi dengan sopan. Program yang dirancang baik menangkap sinyal ini untuk menutup berkas yang terbuka, menulis sisa data, dan memberi tahu rekan-rekannya sebelum benar-benar berakhir. Contoh berikut melahirkan satu proses sleep 300, mengirim SIGTERM kepadanya, lalu memeriksa akibatnya dengan ps.

bash
sleep 300 &
PID=$!
sleep 0.3
ps -o stat=,cmd= -p "$PID"
# kill tanpa opsi mengirim SIGTERM
kill "$PID"
wait "$PID" 2>/dev/null
echo "status keluar: $?"
ps -o stat= -p "$PID"
echo "ps tidak menampilkan apa pun dan keluar dengan status $?"
text Keluaran
S    sleep 300
status keluar: 143
ps tidak menampilkan apa pun dan keluar dengan status 1

Proses sleep tidak menangkap SIGTERM, sehingga sinyal itu langsung mengakhirinya dan ps tidak lagi menemukan baris apa pun untuk PID tersebut. Status keluar yang direkam wait adalah 143, yaitu 128 ditambah nomor sinyal 15, pola yang berlaku untuk setiap proses yang berakhir karena sinyal. Angka ini berulang kali muncul pada skrip dan layanan, sehingga mengenalinya mempercepat pembacaan log.

Setelah kill dikirim, apakah prosesnya benar-benar berhenti perlu diverifikasi, bukan diasumsikan. Pembandingannya mudah dilakukan dengan ps -p PID seperti pada contoh, karena keluaran kosong berarti proses sudah berakhir, sedangkan baris dengan keadaan T berarti proses masih hidup tetapi ditahan. Program yang besar memerlukan waktu sekejap untuk menyelesaikan pembersihannya, sehingga perlu ada jeda beberapa detik sebelum disimpulkan bahwa sinyal gagal.

SIGKILL tidak dapat ditolak#

Sinyal SIGKILL diimplementasikan langsung oleh kernel dan tidak pernah sampai ke tangan program, sehingga tidak bisa ditangkap, ditunda, atau diabaikan. Contoh berikut mengulang pola yang sama dengan kill -9.

bash
sleep 300 &
PID=$!
sleep 0.3
kill -9 "$PID"
wait "$PID" 2>/dev/null
echo "status keluar: $?"
ps -o stat= -p "$PID"
echo "ps tidak menampilkan apa pun dan keluar dengan status $?"
text Keluaran
status keluar: 137
ps tidak menampilkan apa pun dan keluar dengan status 1

Pada sleep, hasil keduanya tampak mirip karena program kecil itu tidak menangkap sinyal apa pun, hanya nomor statusnya yang berbeda menjadi 137, yaitu 128 ditambah 9. Perbedaan yang sesungguhnya baru terlihat pada program yang memang menangani SIGTERM, dan itulah yang diuji pada bagian berikut.

Karena pengirimannya ditangani kernel, SIGKILL bekerja bahkan pada proses yang sedang berputar tanpa henti atau yang mengabaikan SIGTERM, dan itulah alasan keberadaannya. Kasus yang pantas menerima kill -9 adalah proses yang macet total, misalnya program yang berputar dalam perulangan tanpa akhir setelah error dan tidak lagi menanggapi apa pun. Perlu dicatat bahwa proses yang baru dihentikan kadang masih terdaftar pada ps dengan keadaan Z, yaitu zombie, karena proses induknya belum merekam status akhirnya, dan baris semacam itu bukan tanda sinyal gagal.

Perbedaannya pada program yang menangkap sinyal#

Skrip shell dapat menetapkan penangan sinyal (signal handler) dengan trap. Skrip contoh berikut menjaga sebuah berkas penanda, dan penangan SIGTERM-nya menghapus penanda tersebut sebelum keluar.

bash
rm -f penanda
printf '#!/bin/bash\ntrap "rm -f penanda; echo penanda dibersihkan; exit 0" TERM\nwhile true; do sleep 0.2; done\n' > tugas.sh
touch penanda
bash tugas.sh &
PID=$!
sleep 0.3
kill "$PID"
wait "$PID" 2>/dev/null
echo "status keluar: $?"
test -f penanda || echo "penanda sudah dihapus"
text Keluaran
penanda dibersihkan
status keluar: 0
penanda sudah dihapus

SIGTERM ditangkap, penanda dihapus, dan skrip keluar dengan status 0 karena memang berhenti sesuai rencana. Percobaan yang sama dengan SIGKILL berjalan sangat berbeda.

bash
rm -f penanda
touch penanda
bash tugas.sh &
PID=$!
sleep 0.3
kill -9 "$PID"
wait "$PID" 2>/dev/null
echo "status keluar: $?"
test -f penanda && echo "penanda masih ada"
text Keluaran
status keluar: 137
penanda masih ada

Pesan dari penangan sinyal tidak muncul, dan berkas penanda tertinggal karena penangan itu tidak pernah berkesempatan berjalan. Inilah harga SIGKILL: prosesnya pasti berhenti, tetapi semua pembersihan yang seharusnya dilakukan ikut batal. Pola pada skrip kecil ini berlaku sama pada program besar. Layanan web, misalnya, menutup koneksi dan menulis log ketika menerima SIGTERM, sehingga perhentian paksa dengan kill -9 pada layanan semacam itu meninggalkan keadaan yang tidak selesai.

Kesalahan umum#

  • Memakai kill -9 sebagai refleks pertama. Kebiasaan ini menghilangkan kesempatan program merapikan dirinya. Urutan yang sehat adalah kill, menunggu sebentar, memeriksa dengan ps, lalu kill -9 bila prosesnya masih bertahan.
  • Menganggap proses macet hanya karena belum berakhir beberapa ratus milidetik setelah kill. Program yang menangkap SIGTERM memerlukan waktu untuk merapikan dirinya, dan durasinya wajar mencapai beberapa detik pada program dengan banyak koneksi.
  • Mengirim sinyal ke proses milik pengguna lain. Kernel menolaknya dengan pesan error Operation not permitted, dan hanya root yang dapat mengirim sinyal ke proses milik siapa pun.
  • Menyasar PID dari ingatan atau dari log lama. Nomor dapat dipakai ulang, sehingga sinyal bisa terkirim ke proses yang tidak diinginkan. Cari nomor terkini dengan ps terlebih dahulu, atau gunakan perintah seperti pkill yang menerima nama proses sebagai sasarannya. Kecocokan nama tetap diperiksa melalui ps sebelum sinyal dikirim.

Ringkasan#

  • Sinyal adalah pemberitahuan bernomor dari kernel atau proses lain, dan kill beserta kill -l mengirim serta menerjemahkannya dari shell.
  • kill mengirim SIGTERM 15 sebagai permintaan berhenti yang dapat ditangkap, sedangkan kill -9 mengirim SIGKILL 9 yang langsung dijalankan kernel tanpa bisa ditolak.
  • Status keluar 143 dan 137, yaitu 128 ditambah nomor sinyalnya, menandai proses yang berakhir karena sinyal.
  • SIGKILL membatalkan seluruh pembersihan yang ditangani program, sehingga kedudukannya adalah upaya terakhir setelah SIGTERM diberi waktu.

Referensi#