Au cours de leurs échanges avec le système et les programmes, les processus sont amenés à modifier leur état pour indiquer leur disponibilité. Ces changements sont le plus souvent dus à un besoin en ressources mémoire ou matérielle, à l’écriture de données ou encore à une attente (comme une action utilisateur).
Les états les plus connus sont l’état R (en cours d’exécution), S (en sommeil), T (stoppé) ou encore Z (zombie). Ce dernier est particulier car il désigne un processus qui, bien qu’ayant terminé son exécution, reste présent sur le système, en attente d’être pris en compte par son père.
Comment les processus zombies apparaissent ?
Quand un processus se termine normalement, le système désalloue les ressources qui lui avaient été attribuées (code, données, pile d’exécution) tout en conservant son bloc de contrôle. Le système va ensuite attribuer l’état TASK_ZOMBIE au processus fils, qui se traduira par l’état Z (Zombie) que l’on peut observer avec la commande ps. Le processus père sera ensuite prévenu, à l’aide du signal SIGCHLD, que son fils vient de finir sa tâche.
Les processus zombies contrôlés
Lorsque le système envoie le signal SIGCHLD au processus père, ce dernier va récupérer, à l’aide des primitives wait()
ou waitpid()
, le code de retour de son fils terminé. Le père cumulera alors les statistiques de son fils avec les siennes et supprimera son entrée de la table des processus, le fils pourra alors totalement être effacé du système.
En temps normal, l’état zombie d’un processus ne pose aucun problème sur le système tant que le programme a été pensé pour que le père puisse réceptionner l’état de ses fils terminés.
Les processus zombies errants
Si le processus père n’a pas été conçu pour réceptionner le code de retour de chaque processus fils qu’il crée, ces derniers resteront à l’état zombies pendant toute sa durée d’exécution, ce qui peut être problématique si le père engendre à intervalle régulier des fils et s’il n’a pas été conçu pour être arrêté (un serveur, une tâche de fond, …).
Sans cette prise en compte les processus fils zombies disposeront toujours d’un PID et occuperont la table des processus et resteront ainsi présent sur le système.
Comment se débarrasser des processus zombies ?
On ne peut pas… Ils sont déjà morts… La commande kill
n’a aucun effet sur eux.
Le seul recours possible est de directement mettre un terme au processus père, avec par exemple la commande kill
. Les processus fils zombies seront alors adoptés par init
et ce dernier se chargera de les supprimer de la table des processus.
On pourrait penser, à tort, que les processus zombies ne sont pas gênant en soit puisqu’ils ne consomment aucune ressource et qu’ils ont terminés leur tâche. Le problème est que la quantité de processus qu’un système peut créer est limitée et un trop grand nombres de mauvaises synchronisations entre pères et fils entraînera à terme une saturation de la table des processus et bloquera tout le système qui ne pourra plus en créer de nouveaux.
Comment créer une invasion zombie ?
Si vous aimez The Walking Dead je vous propose un script en C qui permet d’étudier les processus Zombies. C’est un script très simple, conçu exprès pour facilement les observer avec l’aide de la commande ps -aux
, à lancer dans un autre terminal à intervalles réguliers.
Script en C pour créer des processus zombies
Ce script permet de générer des processus zombies, il est possible, entre autres, de paramétrer le nombre de zombies à créer et leur durée de vie (temps d’attente).
#include <stdio.h> |
La primitive fork()
permet de créer un processus fils, le PID du processus fils est envoyé au père et la valeur 0 est envoyé au processus enfant. La primitive exit()
quand à elle met fin à un processus et le système va désallouer les ressources auparavant attribuées, sauf l’entrée dans la table des processus. Enfin, l’appel à wait()
permet au processus père d’attendre et de récupérer la terminaison de son fil via le signal SIGCHLD envoyé par le système lors de la terminaison d’un processus.
Compilation
Pour compiler la source du script, intitulé ici ZombieInvader.c, vous pouvez utiliser cette commande :
# gcc -o ZombieInvader ZombieInvader.c
Pour le lancer à partir d’un terminal :
# ./ZombieInvader
Vous devriez voir ceci :
-- Lancement de l'invasion -- |
Après 20 sec, le script fera appel à wait()
et les processus zombies seront supprimés.
Observation avec ps
En lançant, dans un autre terminal, la commande ps -aux
au cours de l’exécution du script, on peut observer le statut Z des 5 processus enfants ainsi que l’annotation <defunct>
en fin de ligne.
# ps -aux |
Il est aussi possible avec les options -axjf
de voir les processus de façon arborescente :
# ps -axjf |
Ces deux commandes peuvent être lancées à tous moments et plusieurs fois lors de l’exécution du script. On remarquera aussi que les processus fils ont bien tous le même PPID (ici 4974), soit le PID le leur père.