web-dev-qa-db-fra.com

Comment est-il possible que kill -9 pour un processus sous Linux n'ait aucun effet?

J'écris un plugin pour mettre en évidence les chaînes de texte automatiquement lorsque vous visitez un site Web. C'est comme les résultats de recherche en surbrillance mais automatique et pour beaucoup de mots; il pourrait être utilisé par les personnes allergiques pour faire ressortir les mots, par exemple, lorsqu'elles naviguent sur un site alimentaire.

Mais j'ai un problème. Lorsque j'essaie de fermer une fenêtre FF vierge et vide, elle bloque tout le processus. Lorsque je tue le processus, toutes les fenêtres disparaissent, mais le processus Firefox reste actif (le PID parent est 1, n'écoute aucun signal, a beaucoup de ressources ouvertes, continue de manger, mais ne bouge pas).

Donc deux questions:

  1. Comment est-il même possible pour un processus de ne pas écouter kill -9 (ni en tant qu'utilisateur ni en tant que root)?

  2. Est-ce que je peux faire autre chose qu'un redémarrage?

[EDIT] Ceci est le processus incriminé:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
digulla  16688  4.3  4.2 784476 345464 pts/14  D    Mar28  75:02 /opt/firefox-3.0/firefox-bin

Idem avec ps -ef | grep firefox

UID        PID  PPID  C STIME TTY          TIME CMD
digulla  16688     1  4 Mar28 pts/14   01:15:02 /opt/firefox-3.0/firefox-bin

C'est le seul processus qui reste. Comme vous pouvez le constater, ce n'est pas un zombie, c'est la course! Il n'écoute pas pour tuer -9, peu importe si je tue par PID ou par nom! Si j'essaie de me connecter avec strace, alors la strace se bloque également et ne peut pas être tuée. Il n'y a pas de sortie non plus. Je suppose que FF se bloque dans une routine du noyau, mais laquelle?

[EDIT2] Basé sur les commentaires de sigjuice: 

ps axopid,comm,wchan

peut vous montrer dans quelle routine de noyau un processus est bloqué. Dans mon cas, le plugin incriminé était Beagle Indexer (openSUSE 11.1). Après avoir désactivé le plugin, FF était redevenu un renard rapide et heureux.

64
Aaron Digulla

Comme indiqué dans les commentaires relatifs au PO, un statut de processus (STAT) de D indique que le processus est dans un état de "veille ininterrompue". En termes réels, cela signifie généralement qu'il attend des E/S et ne peut/ne veut rien faire - y compris la mort - jusqu'à ce que l'opération d'E/S soit terminée.

Les processus dans un état D n'y seront normalement présents que pendant une fraction de seconde avant la fin de l'opération et ils retourneront à R/S. D'après mon expérience, si un processus reste bloqué dans D, il essaie le plus souvent de communiquer avec un système de fichiers NFS inaccessible ou un autre système de fichiers distant, d'essayer d'accéder à un disque dur défaillant ou d'utiliser un composant matériel au moyen d'un pilote de périphérique floconneux. . Dans de tels cas, le seul moyen de récupérer et d’autoriser le processus à mourir est d’obtenir le système fs/drive/hardware de nouveau opérationnel afin que l’E/S puisse se terminer ou d’abandonner et de redémarrer le système. Dans le cas spécifique de NFS, le montage peut également expirer et revenir de l'opération d'E/S (avec un code d'échec), mais cela dépend des options de montage et il est très courant que les montages NFS soient configurés pour attendre indéfiniment .

Ceci est différent d'un processus zombie, qui aura le statut Z.

124
Dave Sherohman

Vérifiez bien que l'identifiant parent est vraiment 1. Si ce n'est pas le cas et qu'il s'agit de firefox, essayez d'abord Sudo killall -9 firefox-bin. Après cela, essayez de supprimer les ID de processus spécifiques individuellement avec Sudo killall -9 [process-id].

Comment est-il même possible pour un processus de ne pas écouter kill -9 (en tant qu'utilisateur ni en tant que root)?

Si un processus a disparu <defunct> et devient ensuite un zombie avec un parent de 1, vous ne pouvez pas le tuer manuellement; seulement init can. Les processus zombies sont déjà morts et ont disparu - ils ont perdu la possibilité d'être tués car ils ne sont plus des processus, il ne reste plus qu'une entrée de table de processus et son code de sortie associé, en attente de collecte. Vous devez tuer le parent et vous ne pouvez pas tuer init pour des raisons évidentes.

Mais voir ici pour plus d’informations générales. Un redémarrage va tout tuer, naturellement.

8
John Feminella

Dernièrement, je me suis retrouvé pris au piège dans Double Fork et je me suis retrouvé sur cette page avant de finalement trouver ma réponse. Les symptômes sont identiques même si le problème n'est pas le même:

  • WYKINWYT: Ce que vous tuez n'est pas ce que vous pensiez

Le code de test minimal est présenté ci-dessous à partir d'un exemple de démon SNMP.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main(int argc, char* argv[])
{
    //We omit the -f option (do not Fork) to reproduce the problem
    char * options[]={"/usr/local/sbin/snmpd",/*"-f","*/-d","--master=agentx", "-Dagentx","--agentXSocket=tcp:localhost:1706",  "udp:10161", (char*) NULL};

    pid_t pid = fork();
    if ( 0 > pid ) return -1;

    switch(pid)
    {
        case 0: 
        {   //Child launches SNMP daemon
            execv(options[0],options);
            exit(-2);
            break;
        }
        default: 
        {
            sleep(10); //Simulate "long" activity

            kill(pid,SIGTERM);//kill what should be child, 
                              //i.e the SNMP daemon I assume
            printf("Signal sent to %d\n",pid);

            sleep(10); //Simulate "long" operation before closing
            waitpid(pid);
            printf("SNMP should be now down\n");

            getchar();//Blocking (for observation only)
            break;
        }
    }
    printf("Bye!\n");
}

Au cours de la première phase, le processus principal (7699) lance le démon SNMP (7700) mais nous pouvons voir que celui-ci est désormais Defunct/Zombie. A côté, nous pouvons voir un autre processus (7702) avec les options que nous avons spécifiées

[nils@localhost ~]$ ps -ef | tail
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7699   2832  0 23:11 pts/0    00:00:00 ./main
nils       7700   7699  0 23:11 pts/0    00:00:00 [snmpd] <defunct>
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7727   3706  0 23:11 pts/1    00:00:00 ps -ef
nils       7728   3706  0 23:11 pts/1    00:00:00 tail

Après les 10 secondes simulées, nous essaierons de tuer le seul processus connu (7700). Ce que nous réussissons enfin avec waitpid (). Mais le processus 7702 est toujours là

[nils@localhost ~]$ ps -ef | tail
root       7431      2  0 23:00 ?        00:00:00 [kworker/u256:1]
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7699   2832  0 23:11 pts/0    00:00:00 ./main
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7751   3706  0 23:12 pts/1    00:00:00 ps -ef
nils       7752   3706  0 23:12 pts/1    00:00:00 tail

Après avoir donné un caractère à la fonction getchar (), notre processus principal se termine mais le démon SNMP avec le pid 7002 est toujours là.

[nils@localhost ~]$ ps -ef | tail
postfix    7399   1511  0 22:58 ?        00:00:00 pickup -l -t unix -u
root       7431      2  0 23:00 ?        00:00:00 [kworker/u256:1]
root       7439      2  0 23:00 ?        00:00:00 [kworker/1:0]
root       7494      2  0 23:03 ?        00:00:00 [kworker/0:1]
root       7544      2  0 23:08 ?        00:00:00 [kworker/0:2]
root       7605      2  0 23:10 ?        00:00:00 [kworker/1:2]
root       7698    729  0 23:11 ?        00:00:00 sleep 60
nils       7702      1  0 23:11 ?        00:00:00 /usr/local/sbin/snmpd -Lo -d --master=agentx -Dagentx --agentXSocket=tcp:localhost:1706 udp:10161
nils       7765   3706  0 23:12 pts/1    00:00:00 ps -ef
nils       7766   3706  0 23:12 pts/1    00:00:00 tail

Conclusion

Le fait que nous ayons ignoré le mécanisme double fork nous a fait penser que l'action de destruction n'a pas abouti. Mais en fait, nous avons simplement tué le mauvais processus !!

En ajoutant l’option -f (Ne pas (double) fourchette), tout se passe comme prévu

1
NGI

Est-il possible que ce processus soit redémarré (par exemple par init) juste au moment où vous le tuez?

Vous pouvez vérifier cela facilement. Si le PID est identique après kill -9 PID, le processus n'a pas été arrêté, mais s'il a changé, le processus a été redémarré.

1
Georg Schölly
Sudo killall -9 firefox

Devrait marcher

EDIT: [PID] changé en firefox

0
karim79

ps -ef | grep firefox; et vous pouvez voir 3 processus, tuez-les tous.

0
ManofPhysics

Vous pouvez également faire un pstree et tuer le parent. Cela garantit que vous obtenez l'intégralité de l'arborescence du processus incriminé et pas seulement la feuille.

0
Eric Holmberg