Secara umum, untuk mematikan proses kami menghasilkan sinyal seperti SIGKILL
, SIGTSTP
dll.
Tetapi bagaimana diketahui siapa yang memerintahkan sinyal tertentu, siapa yang mengirimnya ke proses tertentu, dan secara umum bagaimana sinyal melakukan operasi mereka? Bagaimana cara kerja sinyal secara internal?
kill
signals
architecture
Varun Chhangani
sumber
sumber
Jawaban:
Tampilan 50.000 kaki adalah:
Sinyal dihasilkan oleh kernel secara internal (misalnya,
SIGSEGV
ketika alamat yang tidak valid diakses, atauSIGQUIT
ketika Anda menekan Ctrl+ \), atau oleh program yang menggunakankill
syscall (atau beberapa yang terkait).Jika melalui salah satu syscalls, maka kernel mengkonfirmasi proses pemanggilan memiliki hak yang cukup untuk mengirim sinyal. Jika tidak, kesalahan dikembalikan (dan sinyal tidak terjadi).
Jika itu adalah salah satu dari dua sinyal khusus, kernel bekerja tanpa syarat di dalamnya, tanpa input dari proses target. Dua sinyal khusus adalah SIGKILL dan SIGSTOP. Semua hal di bawah ini tentang tindakan default, memblokir sinyal, dll., Tidak relevan untuk keduanya.
Selanjutnya, kernel mengetahui apa yang harus dilakukan dengan sinyal:
Untuk setiap proses, ada tindakan yang terkait dengan setiap sinyal. Ada banyak default, dan program dapat mengatur yang berbeda menggunakan
sigaction
,,signal
dll. Ini termasuk hal-hal seperti "abaikan sepenuhnya", "matikan proses", "matikan proses dengan dump inti", "hentikan proses", dll.Program juga dapat mematikan pengiriman sinyal ("diblokir"), atas dasar sinyal demi sinyal. Kemudian sinyal tetap tertunda hingga tidak terblokir.
Program dapat meminta bahwa alih-alih kernel mengambil beberapa tindakan itu sendiri, ia mengirimkan sinyal ke proses baik secara sinkron (dengan
sigwait
, et. Al. Atausignalfd
) atau secara tidak sinkron (dengan menyela apa pun yang sedang dilakukan proses, dan memanggil fungsi yang ditentukan).Ada seperangkat sinyal kedua yang disebut "sinyal waktu-nyata", yang tidak memiliki arti khusus, dan juga memungkinkan beberapa sinyal untuk antri (sinyal normal hanya akan mengantri satu dari masing-masing ketika sinyal diblokir). Ini digunakan dalam program multi-utas untuk utas untuk berkomunikasi satu sama lain. Beberapa digunakan dalam implementasi utas POSIX glibc, misalnya. Mereka juga dapat digunakan untuk berkomunikasi antara proses yang berbeda (misalnya, Anda dapat menggunakan beberapa sinyal real-time untuk meminta program fooctl mengirim pesan ke daemon foo).
Untuk tampilan non-50.000 kaki, cobalah
man 7 signal
dan juga dokumentasi internal kernel (atau sumber).sumber
Implementasi sinyal sangat kompleks dan spesifik untuk kernel. Dengan kata lain, kernel yang berbeda akan mengimplementasikan sinyal secara berbeda. Penjelasan yang disederhanakan adalah sebagai berikut:
CPU, berdasarkan pada nilai register khusus, memiliki alamat di memori di mana ia mengharapkan untuk menemukan "tabel deskriptor interupsi" yang sebenarnya merupakan tabel vektor. Ada satu vektor untuk setiap pengecualian yang mungkin, seperti pembagian dengan nol, atau perangkap, seperti INT 3 (debug). Ketika CPU menemukan pengecualian, ia menyimpan flag dan pointer instruksi saat ini di stack dan kemudian melompat ke alamat yang ditentukan oleh vektor yang relevan. Di Linux vektor ini selalu menunjuk ke kernel, di mana ada handler pengecualian. CPU sekarang selesai, dan kernel Linux mengambil alih.
Perhatikan, bahwa Anda juga dapat memicu pengecualian dari perangkat lunak. Misalnya, pengguna menekan CTRL- C, maka panggilan ini pergi ke kernel yang memanggil pengendali pengecualiannya sendiri. Secara umum, ada beberapa cara berbeda untuk sampai ke handler, tetapi terlepas dari hal dasar yang sama terjadi: konteksnya disimpan di stack dan handler pengecualian kernel dilompati.
Pawang pengecualian kemudian memutuskan utas apa yang harus menerima sinyal. Jika sesuatu seperti pembagian-oleh-nol terjadi, maka itu mudah: utas yang menyebabkan perkecualian mendapatkan sinyal, tetapi untuk jenis sinyal lainnya, keputusannya bisa sangat kompleks dan dalam beberapa kasus yang tidak biasa, untaian acak kurang lebih mungkin dapatkan sinyalnya.
Untuk mengirim sinyal apa yang dilakukan oleh kernel adalah pertama-tama mengatur nilai yang menunjukkan jenis sinyal,
SIGHUP
atau apa pun. Ini hanya bilangan bulat. Setiap proses memiliki area memori "pending signal" di mana nilai ini disimpan. Kemudian kernel membuat struktur data dengan informasi sinyal. Struktur ini termasuk sinyal "disposisi" yang mungkin default, abaikan atau tangani. Kernel kemudian memanggil fungsinya sendirido_signal()
. Fase selanjutnya dimulai.do_signal()
pertama memutuskan apakah itu akan menangani sinyal. Misalnya, jika itu adalah pembunuhan , makado_signal()
cukup bunuh prosesnya, akhir cerita. Kalau tidak, itu terlihat pada disposisi. Jika disposisi default, makado_signal()
menangani sinyal sesuai dengan kebijakan standar yang tergantung pada sinyal. Jika disposisi diatur, maka itu berarti ada fungsi dalam program pengguna yang dirancang untuk menangani sinyal yang dimaksud dan penunjuk ke fungsi ini akan berada dalam struktur data yang disebutkan di atas. Dalam hal ini do_signal () memanggil fungsi kernel lain,handle_signal()
, yang kemudian melewati proses beralih kembali ke mode pengguna dan memanggil fungsi ini. Detail dari handoff ini sangat kompleks. Kode ini dalam program Anda biasanya ditautkan secara otomatis ke dalam program Anda ketika Anda menggunakan fungsi-fungsi disignal.h
.Dengan memeriksa nilai sinyal yang tertunda dengan tepat, kernel dapat menentukan apakah proses tersebut menangani semua sinyal, dan akan mengambil tindakan yang tepat jika tidak, yang mungkin menyebabkan proses tidur atau membunuhnya atau tindakan lain, tergantung pada sinyalnya.
sumber
Meskipun pertanyaan ini telah dijawab, izinkan saya memposting alur acara yang terperinci dalam kernel Linux.
Ini sepenuhnya disalin dari posting Linux: Linux Signals - Internal di blog "Linux posts" di sklinuxblog.blogspot.in.
Program Ruang Pengguna Sinyal C
Mari kita mulai dengan menulis program ruang C pengguna sinyal sederhana:
Kode ini memberikan penangan baru untuk sinyal SIGINT. SIGINT dapat dikirim ke proses yang berjalan menggunakan kombinasi tombol Ctrl+ C. Ketika Ctrl+ Cditekan maka sinyal asinkron SIGINT dikirim ke tugas. Ini juga setara dengan mengirim
kill -INT <pid>
perintah di terminal lain.Jika Anda melakukan
kill -l
(itu huruf kecilL
, yang berarti "daftar"), Anda akan mengetahui berbagai sinyal yang dapat dikirim ke proses yang sedang berjalan.Juga kombinasi tombol berikut dapat digunakan untuk mengirim sinyal tertentu:
Jika Anda mengkompilasi dan menjalankan program C di atas maka Anda akan mendapatkan output berikut:
Bahkan dengan Ctrl+ Catau
kill -2 <pid>
proses tidak akan berakhir. Sebaliknya itu akan menjalankan penangan sinyal dan kembali.Bagaimana sinyal dikirim ke proses
Jika kita melihat internal pengiriman sinyal ke suatu proses dan menempatkan Jprobe dengan dump_stack di
__send_signal
fungsi kita akan melihat jejak panggilan berikut:Jadi fungsi utama panggilan untuk mengirim sinyal seperti:
Sekarang semuanya sudah diatur dan perubahan yang diperlukan dilakukan untuk
task_struct
proses.Penanganan sinyal
Sinyal diperiksa / ditangani oleh suatu proses ketika kembali dari panggilan sistem atau jika kembali dari interupsi dilakukan. Pengembalian dari panggilan sistem hadir dalam file
entry_64.S
.Fungsi int_signal function dipanggil dari
entry_64.S
mana memanggil fungsido_notify_resume()
.Mari kita periksa fungsinya
do_notify_resume()
. Fungsi ini memeriksa apakah kitaTIF_SIGPENDING
menetapkan flag ditask_struct
:Panggilan dan sinyal SISTEM
Syscalls "Lambat" misalnya memblokir baca / tulis, menempatkan proses ke status menunggu:
TASK_INTERRUPTIBLE
atauTASK_UNINTERRUPTIBLE
.Tugas dalam status
TASK_INTERRUPTIBLE
akan diubah keTASK_RUNNING
status oleh sinyal.TASK_RUNNING
berarti suatu proses dapat dijadwalkan.Jika dijalankan, penangan sinyalnya akan dijalankan sebelum penyelesaian syscall "lambat". Tidak
syscall
lengkap secara default.Jika
SA_RESTART
flag diatur,syscall
dihidupkan ulang setelah penangan sinyal selesai.Referensi
sumber
kill
perintah, yang merupakan shell builtin). (2c) Meskipun titik koma setelah penutupan}
suatu fungsi bukanlah kesalahan, mereka tidak perlu dan sangat tidak ortodoks. (3) Bahkan jika semuanya benar, itu tidak akan menjadi jawaban yang sangat baik untuk pertanyaan itu. (3a) Pertanyaannya, meskipun agak tidak jelas, tampaknya berfokus pada bagaimana aktor (pengguna dan proses) memulai (yaitu, mengirim ) sinyal. … (Lanjutan)