[UNIX] Zombie killer !
Derrière ce titre de film d’horreur de série B se cache une petite commande Solaris fort utile. Celle qui permet de se débarrasser des processus zombies.
Avant de vous livrer la commande en question, intéressons nous à la notion de processus zombie.
L’état Zombie d’un processus unix est un état de transition normal de la vie, et plutôt de la mort, d’un processus. En effet, une fois son exécution terminée, par un exit() par exemple, un processus passe à l’état zombie – c’est à dire mort, mais pas encore enterré
) – et envoie un signal à son parent pour le notifier de sa propre fin. Il s’agit du signal SIGCHLD (« sig child »). Si celui ci est bien codé, il consomme le signal en utilisant un des appels de type wait ou waitpid ce qui a pour effet de supprimer définitivement le zombie.
Avoir des zombies, est-ce que c’est grave docteur ? Pas vraiment, tant qu’ils ne s’accumulent pas. Ils ne consomment en effet plus de ressource, (mémoire ou CPU) puisqu’ils ont été libérés. La seule chose qu’ils consomment ce sont des entrées dans les tables de processus, ce qui peut à la longue devenir un peu gênant, voire embêtant lorsqu’on atteint le nombre maximal de processus sur un système, mais cela reste rare.
Bon d’accord, mais c’est moche dans un ps, alors comment faire pour s’en débarrasser ?
La bonne vieille méthode: tuer le père. Un processus ne peut pas se trouver sans père, donc lorsqu’un père est tué, ses enfants sont rattachés à leur grand père, et ce jusqu’à l’abraham des processus, j’ai nommé init. Le process init, lui, est bien codé, il est même prévu pour rattrapper le coup aux développeurs distraits. Il fait régulièrement des wait sur ses fils, qui s’ils sont déjà zombies disparaissent comme par enchantement.
L’autre méthode, plus élégante, d’abord parce qu’elle ne fait pas l’apologie du meurtre de processus, mais aussi parce qu’elle permet de nettoyer les zombies sans avoir a terminer un programme potentiellement encore utile pour ce faire: preap. Je vous renvoie au man ce cette commande pour les détails, et en particulier ses quelques restrictions.
Démonstration:
D’abord écrivons un programme mal écrit (oh!):
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int pid;
pid = fork();
if (pid == 0) { // je suis dans le fils
printf("\tJe suis le fils\n");
printf("\tJe dors 10 secondes\n");
sleep(10);
printf("\tje m'arrete\n");
exit(0);
}
else { // je suis dans le pere
printf("Je suis le pere\n");
printf("Mon fils s'appelle: %d\n",pid);
while (1) {
printf("je dors 10 secondes\n");
sleep(10);
}
}
}
Et testons le:
vincent@sauron:~/articles/zombie-killer$ ./test
Je suis le pere
Mon fils s'appelle: 621
je dors 10 secondes
Je suis le fils
Je dors 10 secondes
je dors 10 secondes
je m'arrete
je dors 10 secondes
je dors 10 secondes
je dors 10 secondes
je dors 10 secondes
je dors 10 secondes
je dors 10 secondes
je dors 10 secondes
^C
vincent@sauron:~/articles/zombie-killer$
En parallèle
vincent@sauron:~$ ptree 500
439 /usr/lib/ssh/sshd
494 /usr/lib/ssh/sshd
495 /usr/lib/ssh/sshd
500 -bash
620 ./test
621 ./test
vincent@sauron:~$ ptree 500
439 /usr/lib/ssh/sshd
494 /usr/lib/ssh/sshd
495 /usr/lib/ssh/sshd
500 -bash
620 ./test
621 <defunct>
vincent@sauron:~$ preap 621
preap: unsafe to reap 621; it has been defunct less than 60 seconds
vincent@sauron:~$ preap 621
621: exited with status 0
vincent@sauron:~$ ptree 500
439 /usr/lib/ssh/sshd
494 /usr/lib/ssh/sshd
495 /usr/lib/ssh/sshd
500 -bash
620 ./test
Dommage qu’une telle commande n’existe pas pour linux.





