Як і власне зомбі, процес зомбі неможливо вбити, оскільки він уже мертвий.
Як це відбувається
Коли в Linux / Unix процес гине / закінчується, вся інформація з процесу вилучається із системної пам'яті, залишається лише дескриптор процесу. Процес переходить у стан Z (зомбі). Його батьківський процес отримує сигнал від ядра:, SIGCHLD
це означає, що один з його дочірніх процесів закінчується, переривається або відновлюється після його переривання (у нашому випадку він просто виходить).
Тепер для батьківського процесу потрібно виконати wait()
системний виклик, щоб прочитати стан виходу та іншу інформацію з його дочірнього процесу. Потім дескриптор видаляється з пам'яті, і процес вже не є зомбі.
Якщо батьківський процес ніколи не викликає wait()
syscall, дескриптор процесу зомбі залишається в пам'яті та їсть мізки. Зазвичай ви не бачите зомбі-процесів, тому що вищеописана процедура займає менше часу.
Зоря мертвих
Кожному дескриптору процесу потрібна дуже мала кількість пам'яті, тому кілька зомбі не дуже небезпечні (як у реальному житті). Одна з проблем полягає в тому, що кожен процес зомбі зберігає свій ідентифікатор процесу, а операційна система Linux / Unix має обмежену кількість під-файлів. Якщо неправильно запрограмоване програмне забезпечення генерує багато процесів зомбі, може статися, що процеси вже не можна запускати, оскільки більше ідентифікаторів процесів немає.
Отже, якщо вони є у величезних групах, вони дуже небезпечні (як у багатьох фільмах це демонструється дуже добре)
Як ми можемо захиститися від орди зомбі?
Постріл у голову спрацював би, але я не знаю команди для цього (SIGKILL не буде працювати, оскільки процес уже затих).
Ну, ви можете відправити SIGCHLD через kill до батьківського процесу, але коли він ігнорує цей сигнал, що тоді? Єдиний ваш варіант - вбити батьківський процес і щоб процес init "прийняв" зомбі. wait()
Ініт періодично закликає сискал, щоб очистити своїх дітей-зомбі.
У вашому випадку
У вашому випадку вам потрібно надіслати SIGCHLD до процесу обрізання:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
Потім з іншого терміналу:
root@host:~$ kill -17 $(pgrep cron)
Вихід:
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fff51be39dc, WNOHANG, NULL) = -1 ECHILD (No child processes) <-- Here it happens
rt_sigreturn(0xffffffffffffffff) = -1 EINTR (Interrupted system call)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x403170, [CHLD], SA_RESTORER|SA_RESTART, 0x7fd6a7e9d4a0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({42, 0}, ^C <unfinished ...>
Process 1180 detached
Ви бачите, що wait4()
системний виклик повертається -1 ECHILD, а це означає, що дочірнього процесу немає. Отже, висновок такий: cron реагує на системний виклик SIGCHLD і не повинен форсувати апокаліпсис.