Как возможно, что kill -9 для процесса в Linux не имеет никакого эффекта?

Я пишу плагин, чтобы автоматически выделять текстовые строки при посещении веб-сайта. Это похоже на результаты поиска, но автоматически и для многих слов; он может быть использован для людей с аллергией, чтобы слова действительно выделялись, например, когда они просматривают сайт пищи.

Но у меня проблема. Когда я пытаюсь закрыть пустое свежее окно FF, он каким-то образом блокирует весь процесс. Когда я убиваю процесс, все окна исчезают, но процесс Firefox остается в живых (родительский PID равен 1, не прослушивает никаких сигналов, имеет много ресурсов, открытых, все еще ест процессор, но не сдвинется с места).

Итак, два вопроса:

  • Как вообще возможно, чтобы процесс не прослушивал kill -9 (ни как пользователь, ни как root)?

  • Есть ли что-нибудь, что я могу сделать, но перезагрузка?

[EDIT] Это нарушающий процесс:

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

То же самое с 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

Это единственный процесс. Как вы можете видеть, это не зомби, он работает! Он не слушает kill -9, независимо от того, убил ли я PID или имя! Если я попытаюсь соединиться с strace, то strace также зависает и не может быть убит. Также нет выхода. Я предполагаю, что FF зависает в некоторой программе ядра, но которая?

[EDIT2] Основываясь на отзывах sigjuice:

ps axopid,comm,wchan

может показать вам, в какой программе ядра зависает процесс. В моем случае плагин-нарушитель был индексом Beagle (openSUSE 11.1). После отключения плагина FF снова стала быстрой и счастливой лисицей.

Ответ 1

Как отмечено в комментариях к OP, статус процесса (STAT) D указывает, что процесс находится в состоянии "без прерывания сна". В реальных условиях это обычно означает, что он ожидает ввода-вывода и не может/не будет делать ничего, включая умирание, до тех пор, пока эта операция ввода-вывода не завершится.

Процессы в состоянии D обычно будут присутствовать только на долю секунды до завершения операции, и они возвращаются к R/S. По моему опыту, если процесс застрял в D, он чаще всего пытается общаться с недоступной NFS или другой удаленной файловой системой, пытаясь получить доступ к отказоустойчивому жесткому диску или использовать какой-то элемент аппаратного обеспечения в виде flaky драйвер устройства. В таких случаях единственный способ восстановить и позволить процессу умереть - либо вернуть резервную копию fs/drive/hardware, чтобы выполнить ввод-вывод, либо отказаться и перезагрузить систему. В конкретном случае NFS mount может также в конечном итоге отключиться и вернуться из операции ввода-вывода (с кодом отказа), но это зависит от параметров монтирования, и очень часто для монтирования NFS должны быть установлены ожидания навсегда.

Это отличается от процесса зомби, который будет иметь статус Z.

Ответ 2

Дважды проверьте, что parent-id действительно 1. Если нет, и это firefox, сначала попробуйте sudo killall -9 firefox-bin. После этого попробуйте уничтожить конкретные идентификаторы процесса отдельно с помощью sudo killall -9 [process-id].

Как вообще возможно, чтобы процесс не прослушивал kill -9 (neiter как пользователь или root)?

Если процесс прошел <defunct>, а затем становится зомби с родителем 1, вы можете 'убить его вручную; только init жестяная банка. Процессы зомби уже мертвы и исчезли - они потеряли способность убивать, поскольку они больше не обрабатываются, а только запись таблицы процессов и связанный с ней код выхода, ожидающие сбора. Вам нужно убить родителя, и вы не можете убить init по понятным причинам.

Но см. здесь для получения более общей информации. Перезагрузка, естественно, уничтожит все.

Ответ 3

Возможно ли, что этот процесс будет перезапущен (например, init) только в момент его убийства?

Вы можете легко это проверить. Если после kill -9 PID PID совпадает с тем, то процесс не был убит, но если он изменился, процесс был перезапущен.

Ответ 4

В последнее время я попал в ловушку в ловушке Double Fork и приземлился на эту страницу, прежде чем, наконец, нашел свой ответ. Симптомы идентичны, даже если проблема не то же самое:

  • WYKINWYT: То, что вы убиваете, не то, что вы думали.

Минимальный тестовый код показан ниже на примере демон 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");
}

На первом этапе основной процесс (7699) запускает SNMP-демон (7700), но мы видим, что теперь он является Defunct/Zombie. Кроме того, мы можем увидеть другой процесс (7702) с указанными опциями

[[email protected] ~]$ 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

После имитации 10 секунд мы попытаемся убить единственный процесс, который мы знаем (7700). Что мы, наконец, добились waitpid(). Но Process 7702 все еще здесь

[[email protected] ~]$ 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

После предоставления символа функции getchar() наш основной процесс завершается, но демон SNMP с pid 7002 все еще здесь

[[email protected] ~]$ 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

Заключение

Тот факт, что мы проигнорировали механизм double fork, заставил нас думать, что действие kill не получилось. Но на самом деле мы просто убили неправильный процесс.

Добавив параметр -f (Do not (Double) Fork), все идет как ожидается

Ответ 5

sudo killall -9 firefox

Должен работать

EDIT: [PID] изменен на firefox

Ответ 6

ps -ef | grep firefox; и вы можете видеть 3 процесса, убить их всех.

Ответ 7

Вы также можете сделать pstree и убить родителя. Это гарантирует, что вы получите все дерево обработки, а не только лист.