Pour répondre à cette question, vous devez comprendre comment les signaux sont envoyés à un processus et comment un processus existe dans le noyau.
Chaque processus est représenté comme un task_struct
à l'intérieur du noyau (la définition est dans le sched.h
fichier d' en- tête et commence ici ). Cette structure contient des informations sur le processus; par exemple le pid. Les informations importantes se trouvent sur la ligne 1566 où le signal associé est stocké. Ce paramètre n'est défini que si un signal est envoyé au processus.
Un processus mort ou un processus zombie a toujours un task_struct
. La structure reste, jusqu'à ce que le processus parent (naturel ou par adoption) ait appelé wait()
après la réception SIGCHLD
pour récolter son processus enfant. Lorsqu'un signal est envoyé, le signal_struct
est réglé. Peu importe que le signal soit capturable ou non, dans ce cas.
Les signaux sont évalués à chaque fois que le processus s'exécute. Ou pour être exact, avant que le processus ne s'exécute. Le processus est alors en l' TASK_RUNNING
état. Le noyau exécute la schedule()
routine qui détermine le processus suivant en fonction de son algorithme de planification. En supposant que ce processus est le prochain processus en cours, la valeur de signal_struct
est évaluée, qu'il y ait ou non un signal en attente à traiter. Si un gestionnaire de signal est défini manuellement (via signal()
ou sigaction()
), la fonction enregistrée est exécutée, sinon l' action par défaut du signal est exécutée. L'action par défaut dépend du signal envoyé.
Par exemple, le SIGSTOP
gestionnaire par défaut du signal changera l'état du processus actuel en TASK_STOPPED
puis s'exécutera schedule()
pour sélectionner un nouveau processus à exécuter. Remarquez, SIGSTOP
n'est pas capturable (comme SIGKILL
), donc il n'y a aucune possibilité d'enregistrer un gestionnaire de signal manuel. En cas de signal inaccessible, l'action par défaut sera toujours exécutée.
À votre question:
Un processus défunt ou mort ne sera jamais déterminé par l'ordonnanceur comme étant à TASK_RUNNING
nouveau dans l' état. Ainsi, le noyau n'exécutera jamais le gestionnaire de signal (par défaut ou défini) pour le signal correspondant, quel que soit le signal. Par conséquent, le exit_signal
ne sera plus jamais réglé. Le signal est « livré » au processus en définissant le signal_struct
dans task_struct
du processus, mais rien d' autre qui va se passer, parce que le processus ne fonctionnera jamais à nouveau. Il n'y a pas de code à exécuter, tout ce qui reste du processus est cette structure de processus.
Cependant, si le processus parent recueille ses enfants wait()
, le code de sortie qu'il reçoit est celui lorsque le processus est "initialement" mort. Peu importe s'il y a un signal en attente de traitement.
kill
elle-même renvoie-t-elle 0 ou 1?Un processus zombie est fondamentalement déjà mort. La seule chose est que personne n'a encore reconnu sa mort, alors il continue d'occuper une entrée dans la table de processus ainsi qu'un bloc de contrôle (la structure que le noyau Linux maintient pour chaque thread en activité). D'autres ressources comme les verrous obligatoires sur les fichiers, les segments de mémoire partagée, les sémaphores, etc. sont récupérés.
Vous ne pouvez pas les signaler car personne ne peut agir sur ce signal. Même des signaux fatals comme KILL sont inutiles car le processus a déjà terminé son exécution. Vous pouvez vous essayer:
Ici, je lance un processus qui bifurque et dort avant d'attendre son enfant. L'enfant ne fait que dormir un peu. Vous pouvez tuer l'enfant quand il dort ou juste après sa sortie pour voir la différence:
la source
ruby -e "loop while fork { exit! }"
... imgur.com/SoRXErm