Jak mogę zabić <niedziałający> proces, którego rodzicem jest init?

27

Transmisja zawiesza się sporadycznie na moim serwerze NAS. Jeśli wyślę SIGTERM, nie zniknie z listy procesów, a <defunct>obok pojawi się etykieta. Jeśli wyślę SIGKILL, nadal nie zniknie i nie mogę zakończyć rodzica, ponieważ rodzic jest init. Jedynym sposobem, aby pozbyć się procesu i zrestartować Transmisję, jest ponowne uruchomienie.

Zdaję sobie sprawę, że najlepszą rzeczą, jaką mogę zrobić, to spróbować naprawić Transmission (i próbowałem), ale jestem nowicjuszem w kompilacji i chciałem się upewnić, że moje torrenty się skończą, zanim zacznę z tym błądzić.

Andy E.
źródło
3
Nikt nie twierdzi, że oczywisty ... <funkcjonalny> proces należący do „init” powinien być niemożliwy! To bardzo dziwna situtacja! Jesteś pewny?
JoelFan
@JelFan: Po prostu szukałem tego, aby upewnić się, że nie zapomnę czegoś ważnego. Zombie, które są dziećmi, initpowinny zniknąć dość szybko, ponieważ initokresowo czeka na dzieci, ponieważ jedno z jego wielu typowych zadań ... jest <defunct>takie samo jak zombie?
D.Shawley,
1
nevermind ... <defunct>jest dokładnie taki sam jak zombie. initbędzie czekać na swoje dzieci, więc teoretycznie nigdy nie powinno się to zdarzyć. Zastanawiam się, co się stanie, jeśli wyślesz wiadomość SIGCHLDna initadres?
D.Shawley,
@JelFan: tak, jestem pewien. Wartość PPID wynosiła 1 (init), więc nie można było PODPISOWAĆ procesu.
Andy E
3
podobny do unix.stackexchange.com/a/5648
tshepang

Odpowiedzi:

35

Nie możesz zabić <defunct>procesu (znanego również jako proces zombie), ponieważ jest on już martwy. System przechowuje procesy zombie dla rodzica w celu zebrania statusu wyjścia. Jeśli rodzic nie odbierze statusu wyjścia, procesy zombie pozostaną na zawsze. Jedynym sposobem na pozbycie się procesów zombie jest zabicie rodzica. Jeśli rodzic jest init, możesz tylko zrestartować komputer.

Procesy zombie nie zajmują prawie żadnych zasobów, więc nie ma kosztu wydajności, pozwalając im pozostać. Chociaż procesy wokół zombie zwykle oznaczają błąd w niektórych programach. Init powinien zwykle zebrać wszystkie dzieci. Jeśli init ma dzieci zombie, to w init jest błąd (lub coś innego, ale to błąd).

http://en.wikipedia.org/wiki/Zombie_process

lesmana
źródło
9
initnigdy nie może mieć dzieci zombie. Z artykułu w Wikipedii: Gdy proces traci swojego rodzica, init staje się jego nowym rodzicem. Init okresowo wykonuje wywołanie systemowe wait, aby czerpać zombie z init jako rodzicem. Jednym z initobowiązków jest zbieranie sierot i zombie bez rodziców.
D.Shawley,
14
@ D.Shawley: initmoże mieć jednak błędy. Podczas wymiany init runitwystąpił błąd, który powoduje ten problem.
camh
2
init może mieć nieczynne dzieci, może z powodu błędu, ale może. Ponieważ patrzę teraz na jedną.
studgeek
Jest ten program, który uruchomiłem z terminala i wszedłem w stan nieczynny. Jak wyjaśnił @lesmana, kiedy zamknąłem terminal (rodzica), program wyszedł poprawnie.
mk ..
6

Każdy, kto próbuje naprawić kod źródłowy Transmission C, powinien przeczytać o sztuczce polegającej na „podwójnym rozwidleniu”, aby uniknąć zombie i programów obsługi sygnałów ... oraz o tym, jak można jej użyć jako części inteligentnej funkcji odradzania variadic (patrz Odradzanie w Uniksie ).

excerpt from: 
   "Spawning in Unix", http://lubutu.com/code/spawning-in-unix

Double fork
This trick lets you spawn processes whilst avoiding zombies, without 
installing any signal handler. The first process forks and waits for its 
child; the second process forks and immediately exits and is reaped;
the third process is adopted by init, and executes the desired program. 
All zombies accounted for, since init is always waiting.

if(fork() == 0) {
   if(fork() == 0) {
       execvp(file, argv);
       exit(EXIT_FAILURE);
   }
   exit(EXIT_SUCCESS);
}
wait(NULL);
nazar
źródło
1
Podwójny widelec zapobiega procesom zombie, zmuszając jądro do ustawienia swojego rodzica na PID 1, który ma oczyścić zombie. Wygląda na to, że Transmisja już to robi, ponieważ jej rodzic jest już w trakcie procesu 1.
Jander
1
Tutaj jest wiele problemów. # 1: Tylko rodzic powinien zadzwonić exit(3); dzieci powinny _exit(2)zamiast tego zadzwonić (w przeciwnym razie dostaniesz wiele różnych kolorów, między innymi). # 2: Przydałoby execvp(3)się, perror(3)jeśli się nie powiedzie. # 3: Powinieneś użyć signal(SIGCHLD, SIG_IGN)zamiast tego całego bałaganu.
Kevin