GNU/Linux >> Znalost Linux >  >> Linux

Co se stane, když pošlete SIGKILL do Zombie Process v Linuxu?

Chcete-li odpovědět na tuto otázku, musíte pochopit, jak jsou signály odesílány procesu a jak proces existuje v jádře.

Každý proces je reprezentován jako task_struct uvnitř jádra (definice je v sched.h hlavičkový soubor a začíná zde). Tato struktura obsahuje informace o procesu; například pid. Důležitá informace je na řádku 1566, kde je uložen související signál. Toto je nastaveno pouze v případě, že je procesu odeslán signál.

Mrtvý proces nebo zombie proces má stále task_struct . Struktura zůstává, dokud nadřazený proces (přirozený nebo adoptovaný) nezavolá wait() po obdržení SIGCHLD sklidit svůj dětský proces. Když je odeslán signál, signal_struct je nastaven. V tomto případě nezáleží na tom, zda je signál zachytitelný nebo ne.

Signály se vyhodnocují pokaždé, když proces běží. Nebo přesněji před proces by běh. Proces je pak v TASK_RUNNING Stát. V jádře běží schedule() rutina, která určuje další běžící proces podle svého plánovacího algoritmu. Za předpokladu, že tento proces je dalším běžícím procesem, hodnota signal_struct se vyhodnocuje, zda existuje čekací signál, který má být zpracován, či nikoli. Pokud je obsluha signálu definována ručně (prostřednictvím signal() nebo sigaction() ), provede se registrovaná funkce, pokud to není výchozí akce signálu je proveden. Výchozí akce závisí na odesílaném signálu.

Například SIGSTOP výchozí handler signálu změní aktuální stav procesu na TASK_STOPPED a poté spusťte schedule() vyberte nový proces ke spuštění. Upozornění, SIGSTOP není zachytitelný (jako SIGKILL ), proto není možné zaregistrovat ruční obsluhu signálu. V případě nezachytitelného signálu bude vždy provedena výchozí akce.

K vaší otázce:

Plánovač nikdy neurčí, že zaniklý nebo mrtvý proces je v TASK_RUNNING znovu stát. Jádro tedy nikdy nespustí obslužný program signálu (výchozí nebo definovaný) pro odpovídající signál, bez ohledu na to, který signál byl. Proto exit_signal už nikdy nebude nastaveno. Signál je „dodán“ procesu nastavením signal_struct v task_struct procesu, ale nic jiného se nestane, protože proces se již nikdy nespustí. Neexistuje žádný kód ke spuštění, z procesu zbývá pouze struktura procesu.

Pokud však nadřazený proces sklízí své potomky o wait() , výstupní kód, který obdrží, je ten, kdy proces „zpočátku“ zemřel. Nezáleží na tom, zda existuje signál čekající na zpracování.


Proces zombie je v podstatě již mrtvý. Jediná věc je, že jeho smrt zatím nikdo nepřiznal, takže pokračuje v zabírání položky v tabulce procesů a také v řídicím bloku (struktura, kterou jádro Linuxu udržuje pro každé vlákno v činnosti). Ostatní zdroje, jako jsou povinné uzamčení souborů, segmenty sdílené paměti, semafory atd., jsou získány zpět.

Nemůžete jim dát signál, protože na tento signál nikdo nemůže reagovat. Dokonce i fatální signály jako KILL jsou k ničemu, protože proces již ukončil své provádění. Můžete to zkusit sami:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
    pid_t pid = fork();

    if (pid == -1)
        exit(-1);

    if (pid > 0) {
        //parent
        printf("[parent]: I'm the parent, the pid of my child is %i\n"
            "I'll start waiting for it in 10 seconds.\n", pid);
        sleep(10);
        int status;
        wait(&status);

        if (WIFSIGNALED(status)) {
            printf("[parent]: My child has died from a signal: %i\n", WTERMSIG(status));
        } else if (WIFEXITED(status)) {
            printf("[parent]: My child has died from natural death\n");
        } else {
            printf("[parent]: I don't know what happened to my child\n");
        }
    } else {
        //child
        printf("[child]: I'm dying soon, try to kill me.\n");
        sleep(5);
        printf("[child]: Dying now!\n");
    }

    return 0;
}

Zde začínám proces, který se rozvětvuje a spí, než čeká na své dítě. Dítě nedělá nic jiného, ​​než že trochu spí. Můžete zabít dítě, když spí, nebo těsně poté, co odejde, abyste viděli rozdíl:

$ make zombie 
cc     zombie.c   -o zombie

$ ./zombie    
[parent]: I'm the parent, the pid of my child is 16693
I'll start waiting for it in 10 seconds.
[child]: I'm dying soon, try to kill me.
# Here, I did "kill -15 16693" in another console
[parent]: My child has died from a signal: 15

$ ./zombie
[parent]: I'm the parent, the pid of my child is 16717
I'll start waiting for it in 10 seconds.
[child]: I'm dying soon, try to kill me.
[child]: Dying now!
# Here, I did "kill -15 16717" in another console
[parent]: My child has died from natural death

Linux
  1. Jak zabít proces zombie na Linuxu

  2. Zabíjení zombie, styl Linuxu

  3. Linux – Kdy nemám zabít -9 A proces?

  1. Co dělá program, když je odeslán signál Sigkill?

  2. UNIX / Linux:3 způsoby odesílání signálu do procesů

  3. Základy signálů Linuxu – část I

  1. Kdy je setsid() užitečné nebo proč potřebujeme seskupovat procesy v Linuxu?

  2. Co dělat, když Ctrl + C nemůže zabít proces?

  3. Jaká je definice relace v linuxu?