Come gli zombi reali, un processo di zombi non può essere ucciso, perché è già morto.
Come succede
Quando in Linux / Unix un processo muore / termina tutte le informazioni dal processo vengono rimosse dalla memoria di sistema, rimane solo il descrittore di processo. Il processo entra nello stato Z (zombie). Il suo processo genitore riceve un segnale dal kernel:, SIGCHLD
ciò significa che uno dei suoi processi figlio esce, viene interrotto o riprende dopo essere stato interrotto (nel nostro caso semplicemente esce).
Il processo padre ora deve eseguire la wait()
syscall per leggere lo stato di uscita e altre informazioni dal suo processo figlio. Quindi il descrittore viene rimosso dalla memoria e il processo non è più uno zombi.
Se il processo genitore non chiama mai il wait()
syscall, il descrittore del processo zombi rimane nella memoria e mangia il cervello. Normalmente non vedi processi di zombi, perché la procedura sopra richiede meno tempo.
L'alba dei morti
Ogni descrittore di processo ha bisogno di una quantità molto piccola di memoria, quindi alcuni zombi non sono molto pericolosi (come nella vita reale). Un problema è che ogni processo di zombie mantiene il suo id di processo e un sistema operativo Linux / Unix ha un numero limitato di pid. Se un software programmato in modo errato genera molti processi zombi, può accadere che i processi non possano più essere avviati perché non sono più disponibili ID di processo.
Quindi, se fanno parte di grandi gruppi, sono molto pericolosi (come in molti film è dimostrato molto bene)
Come possiamo difenderci da un'orda di zombi?
Un colpo in testa avrebbe funzionato, ma non conosco il comando per quello (SIGKILL non funzionerà perché il processo è già morto).
Bene, puoi inviare SIGCHLD tramite kill al processo genitore, ma quando ignora questo segnale, e allora? La tua unica opzione è di uccidere il processo genitore e che il processo init "adotti" lo zombi. Init chiama periodicamente la wait()
squallida per ripulire i suoi figli di zombi.
Nel tuo caso
Nel tuo caso, devi inviare SIGCHLD al processo crond:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
Quindi da un altro terminale:
root@host:~$ kill -17 $(pgrep cron)
L'output è:
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
Vedete che la wait4()
syscall restituisce -1 ECHILD, il che significa che non esiste alcun processo figlio. Quindi la conclusione è: cron reagisce al syscall SIGCHLD e non dovrebbe forzare l'apocalisse.