Kadang-kadang setiap kali saya menulis sebuah program di Linux dan crash karena semacam bug, itu akan menjadi proses yang tidak pernah terputus dan terus berjalan selamanya sampai saya me-restart komputer saya (bahkan jika saya logout). Pertanyaan saya adalah:
- Apa yang menyebabkan proses menjadi tidak terputus?
- Bagaimana saya menghentikan hal itu terjadi?
- Ini mungkin pertanyaan bodoh, tetapi apakah ada cara untuk menghentikannya tanpa me-restart komputer saya?
linux
scheduling
preemption
Jason Baker
sumber
sumber
TASK_UNINTERUPTIBLE
keadaan kapan pun sistem tidak dalam keadaan diam, sehingga dengan paksa mengumpulkan data, menunggu untuk mengirimkan begitu pengguna super keluar? Ini akan menjadi tambang emas bagi peretas untuk mengambil informasi, kembali ke keadaan zombie, dan mengirimkan informasi melalui jaringan saat idle. Beberapa dapat berpendapat bahwa ini adalah salah satu cara untuk menciptakanBlackdoor
kekuatan untuk itu, untuk masuk dan keluar dari sistem apa pun yang diinginkan. Saya sangat percaya celah ini bisa disegel untuk selamanya, dengan menghilangkan `TASK_UNINTERUPTIBJawaban:
Proses yang tidak terputus adalah proses yang terjadi pada panggilan sistem (fungsi kernel) yang tidak dapat diganggu oleh sinyal.
Untuk memahami apa artinya itu, Anda perlu memahami konsep panggilan sistem yang interruptible. Contoh klasiknya adalah
read()
. Ini adalah panggilan sistem yang dapat memakan waktu lama (detik) karena berpotensi melibatkan pemintalan hard drive, atau menggerakkan kepala. Selama sebagian besar waktu ini, proses akan tidur, menghalangi perangkat keras.Sementara proses sedang tidur di system call, ia dapat menerima sinyal asinkron Unix (katakanlah, SIGTERM), kemudian terjadi hal berikut:
Kembali lebih awal dari panggilan sistem memungkinkan kode ruang pengguna untuk segera mengubah perilakunya sebagai respons terhadap sinyal. Misalnya, mengakhiri dengan bersih sebagai reaksi terhadap SIGINT atau SIGTERM.
Di sisi lain, beberapa panggilan sistem tidak diizinkan terganggu dengan cara ini. Jika sistem memanggil warung untuk beberapa alasan, prosesnya dapat tetap tanpa batas dalam kondisi yang tidak dapat diselesaikan ini.
LWN memuat artikel bagus yang menyentuh topik ini pada bulan Juli.
Untuk menjawab pertanyaan awal:
Cara mencegah hal ini terjadi: cari tahu driver mana yang menyebabkan masalah Anda, dan apakah berhenti menggunakan, atau menjadi hacker kernel dan memperbaikinya.
Cara membunuh proses tanpa gangguan tanpa me-reboot: entah bagaimana membuat panggilan sistem berakhir. Seringkali cara paling efektif untuk melakukan ini tanpa menekan saklar daya adalah dengan menarik kabel listrik. Anda juga bisa menjadi peretas kernel dan membuat driver menggunakan TASK_KILLABLE, seperti yang dijelaskan dalam artikel LWN.
sumber
Ketika suatu proses pada mode pengguna, itu dapat terganggu kapan saja (beralih ke mode kernel). Ketika kernel kembali ke mode pengguna, ia memeriksa apakah ada sinyal yang tertunda (termasuk yang digunakan untuk mematikan proses, seperti
SIGTERM
danSIGKILL
). Ini berarti suatu proses dapat dibunuh hanya setelah kembali ke mode pengguna.Alasan suatu proses tidak dapat dimatikan dalam mode kernel adalah karena berpotensi merusak struktur kernel yang digunakan oleh semua proses lain di mesin yang sama (cara yang sama membunuh thread dapat berpotensi merusak struktur data yang digunakan oleh utas lain dalam proses yang sama) .
Ketika kernel perlu melakukan sesuatu yang bisa memakan waktu lama (menunggu pada pipa yang ditulis oleh proses lain atau menunggu perangkat keras untuk melakukan sesuatu, misalnya), ia tidur dengan menandai dirinya sebagai tidur dan memanggil penjadwal untuk beralih ke yang lain. proses (jika tidak ada proses non-tidur, itu beralih ke proses "dummy" yang memberitahu CPU untuk sedikit memperlambat dan duduk dalam satu lingkaran - loop menganggur).
Jika sinyal dikirim ke proses tidur, itu harus dibangunkan sebelum akan kembali ke ruang pengguna dan dengan demikian memproses sinyal yang tertunda. Di sini kita memiliki perbedaan antara dua jenis tidur utama:
TASK_INTERRUPTIBLE
, tidur yang terputus. Jika suatu tugas ditandai dengan bendera ini, ia sedang tidur, tetapi dapat dibangunkan oleh sinyal. Ini berarti kode yang menandai tugas sebagai tidur mengharapkan sinyal yang mungkin, dan setelah bangun akan memeriksanya dan kembali dari panggilan sistem. Setelah sinyal ditangani, panggilan sistem berpotensi dapat dimulai kembali secara otomatis (dan saya tidak akan menjelaskan lebih lanjut tentang cara kerjanya).TASK_UNINTERRUPTIBLE
, tidur tanpa gangguan. Jika tugas ditandai dengan bendera ini, ia tidak diharapkan dibangunkan oleh apa pun selain apa pun yang ditunggu, baik karena tidak dapat dengan mudah dimulai kembali, atau karena program mengharapkan panggilan sistem menjadi atom. Ini juga dapat digunakan untuk tidur yang dikenal sangat singkat.TASK_KILLABLE
(disebutkan dalam artikel LWN yang ditautkan oleh jawaban ddaa) adalah varian baru.Ini menjawab pertanyaan pertama Anda. Mengenai pertanyaan kedua Anda: Anda tidak dapat menghindari tidur tanpa gangguan, mereka adalah hal yang normal (itu terjadi, misalnya, setiap kali proses membaca / menulis dari / ke disk); Namun, mereka harus bertahan hanya sepersekian detik. Jika mereka bertahan lebih lama, biasanya itu berarti masalah perangkat keras (atau masalah driver perangkat, yang terlihat sama dengan kernel), di mana driver perangkat sedang menunggu perangkat keras untuk melakukan sesuatu yang tidak akan pernah terjadi. Ini juga bisa berarti Anda menggunakan NFS dan server NFS sedang down (menunggu server untuk pulih; Anda juga dapat menggunakan opsi "intr" untuk menghindari masalah).
Akhirnya, alasan Anda tidak dapat memulihkan adalah alasan yang sama dengan kernel menunggu sampai kembali ke mode pengguna untuk mengirimkan sinyal atau mematikan proses: itu berpotensi merusak struktur data kernel (kode menunggu pada tidur interruptible dapat menerima kesalahan yang memberitahu itu untuk kembali ke ruang pengguna, tempat proses dapat dimatikan; kode yang menunggu pada waktu tidur tanpa gangguan tidak mengharapkan kesalahan).
sumber
Proses tanpa gangguan BIASANYA menunggu I / O mengikuti kesalahan halaman.
Pertimbangkan ini:
Proses / tugas tidak dapat diganggu dalam kondisi ini, karena tidak dapat menangani sinyal apa pun; jika itu terjadi, kesalahan halaman lain akan terjadi dan itu akan kembali ke tempat semula.
Ketika saya mengatakan "proses", saya benar-benar berarti "tugas", yang di Linux (2.6) secara kasar diterjemahkan menjadi "utas" yang mungkin atau mungkin tidak memiliki entri "grup grup" individual di / proc
Dalam beberapa kasus, mungkin menunggu lama. Contoh khas dari ini adalah ketika file executable atau mmap'd pada sistem file jaringan di mana server telah gagal. Jika I / O akhirnya berhasil, tugas akan berlanjut. Jika akhirnya gagal, tugas umumnya akan mendapatkan SIGBUS atau sesuatu.
sumber
Untuk pertanyaan ke-3 Anda: Saya pikir Anda dapat membunuh proses yang tidak terputus dengan menjalankan
sudo kill -HUP 1
. Ini akan restart init tanpa mengakhiri proses yang berjalan dan setelah menjalankannya, proses saya yang tidak pernah terputus hilang.sumber
Jika Anda berbicara tentang proses "zombie" (yang ditetapkan sebagai "zombie" dalam output ps), maka ini adalah catatan yang tidak berbahaya dalam daftar proses menunggu seseorang untuk mengumpulkan kode pengembaliannya dan itu bisa diabaikan dengan aman.
Bisakah Anda jelaskan apa dan "proses tanpa gangguan" untuk Anda? Apakah itu selamat dari "kill -9" dan bahagia chugs bersama? Jika demikian, maka macet di beberapa syscall, yang macet di beberapa driver, dan Anda terjebak dengan proses ini sampai reboot (dan kadang-kadang lebih baik untuk reboot segera) atau membongkar driver yang relevan (yang tidak mungkin terjadi) . Anda bisa mencoba menggunakan "strace" untuk mencari tahu di mana proses Anda macet dan menghindarinya di masa depan.
sumber