|
|
  |
Борьба с процессами зомби, Программирование под Линукс |
|
|
|
Jan 20 2007, 20:10
|

Частый гость
 
Группа: Свой
Сообщений: 120
Регистрация: 17-02-06
Из: Харьков, Украина
Пользователь №: 14 419

|
Ситуация следующая: есть процесс, который запускается по автозапуску системы. Проблема: процесс при неизвесных обстоятельствах вылетает. Причины: разные java script:emoticon(':)', 'smid_2'). Возможно это утечка памяти, аппаратный сбой (программа работает с драйверами устройств), ошибка при работе с памятью и т. д. Мне нужно отследить "вылетание", и заново запустить программу. Я решил сделать это при помощи скрипта (см. влож. файл), который я поместил в автозапуск (вместо самой программы). Скрипт простой (напомню, что pidof - команда, которая возвращает pid процесса по имени, и если процесса нет, возвращает 0). Все работает, когда программы выходит по exit(0). Но вот при segmentation fault скрипт не помогает, так как процесс становиться зомби (т.е. имеет pid != 0). Подскажите почему, или предложите свой вариант.
|
|
|
|
|
Jan 21 2007, 21:46
|
Местный
  
Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458

|
Цитата(InvisibleFed @ Jan 21 2007, 08:11)  Известное мне определение процесса зомби - процесс не имеющий родителя (в случае, когда родител мертв, а потомок остался жив). Может посмотреть, жив ли родитель процесса? Если мертв - значит твой процесс - зомби. Почти так да не совсем: - зомби - это всегда завершившийся процесс (а не завершившийся родитель) ... - процесс становится зомби, когда он отправляет по завершению SIGCHLD - а его некому обработать, например процесс родитель просто не обрабатывает его, например, не ожидает завершения на wait() или waitpid().... - ... можете в запускающем процессе просто добавить пустой обработчик SIGCHLD  ... Цитата(InvisibleFed @ Jan 21 2007, 08:11)  Кажды процесс, насколько я помню хранит pid родителя. pid_t getppid( void );
|
|
|
|
|
Jan 22 2007, 11:20
|
Местный
  
Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458

|
Цитата(snedelko @ Jan 22 2007, 11:50)  Вообще, с процессами зомби немного знаком - боролся я с ними, вызывая в обработчике SIGCHLD функцию wait(). В моей ситуации родителем кто является? Скрипт? Объясните пожалуйста. Если скрипт - то есть ли команда - аналог функции wait()? И подскажите мне вот в чем: мой скрипт срабатывает около 3-х раз (в ситуации, когда программа завершается сама (по exit)), а на 4-й раз появляются зомби. Откуда? И почему не появлялись раньше? А вот когда программа завершается по segmentation fault (то бишь её рубит Линукс, тем же kill наверно), то зомби появляються СРАЗУ.... Я мало что понял из этого объяснения  ... Скрипт не может быть родителем  - родителем может быть только породивший процесс, это может быть, например, скриптовый интерпретатор, выполняющий ваш скрипт... P.S. предложение-подсказка - как разобраться в вашей trouble: - сделайте над своим процессом пустую "обёртку", которая будет только exec/spawn ваш процесс... - в ней вы можете перехватывать - наблюдать - обрабатывать все события... - разобравшись что происходит - выбросите обёртку  .
|
|
|
|
|
Jan 23 2007, 09:56
|
Местный
  
Группа: Свой
Сообщений: 401
Регистрация: 18-11-06
Из: Хабаровск
Пользователь №: 22 469

|
Цитата - зомби - это всегда завершившийся процесс (а не завершившийся родитель) ... - процесс становится зомби, когда он отправляет по завершению SIGCHLD - а его некому обработать, например процесс родитель просто не обрабатывает его, например, не ожидает завершения на wait() или waitpid().... А если процесс еще не завершился, а родитель уже откинулся - как ни крути, а процесс уже по любому зомби (его просто некому будет убить по завершению). Если родитель еще жив и по каким-то причинам не может обработать SIGCHLD - процесс не может считаться зомби, т. к. потенциально родитель еще может его кончить. Интересно, что произойдет с родителем, если он не будет "ждать детей" (wait, waitpid) - он просто заврешиться и все потомки станут зомби. Тонкости, конечно, но все что изложил Olej умещается в моем определении зомби. Или существет пример, когда оно неверно?
|
|
|
|
|
Jan 23 2007, 15:13
|
Группа: Новичок
Сообщений: 9
Регистрация: 23-01-07
Пользователь №: 24 693

|
Цитата(snedelko @ Jan 23 2007, 11:13)  А если процесс зомби, то потоки, запущенные им, тоже зомби? И вообще, тонкостей тут куча, где бы про это подробно почитать ? Вот: Цитата Если же потомок уже завершил работу, а предок не готов принять от системы сигнал об этом событии, то потомок не исчезает полностью, а превращается в "зомби" (zombie) Процесс зомби, следовательно завершил работу и не может принимать сигналы. Потомки станут зомби, когда завершат свою работу. Вот Вам еще несколько цитат: Цитата Если родительский процесс по какой-то причине завершится раньше дочернего, последний становится "сиротой" (orphaned process). "Сироты" автоматически "усыновляются" программой init, выполняющейся в процессе с номером 1, которая и принимает сигнал об их завершении.
Если же потомок уже завершил работу, а предок не готов принять от системы сигнал об этом событии, то потомок не исчезает полностью, а превращается в "зомби" (zombie); в поле Stat такие процессы помечаются буквой Z. Зомби не занимает процессорного времени, но строка в таблице процессов остается, и соответствующие структуры ядра не освобождаются. После завершения родительского процесса "осиротевший" зомби на короткое время также становится потомком init, после чего уже "окончательно умирает". Цитата Последнее из состояний процесса, достижимых внутренней синхронизацией, есть состояние промежуточного завершения текущего процесса - SZOMB (состояние "зомби"). Состояние "зомби" имеет место, если процесс-потомок завершается по системному вызову exit или по сигналу до планируемой реализации системного вызова wait в процессе-предке. При этом образ завершившегося процесса освобождает адресное пространство, но его дескриптор временно сохраняется в таблице процессов, чтобы обеспечить корректную обработку системного вызова wait в процессе-предке. Цитата В состоянии "зомби" процесс не имеет образа в RAM, но информация о нем сохраняется в таблице процессов. Он не поедает ресурсы, но теоретически могут кончится PID'ы.
Напрямую зомби не убить, нужно уничтожить родительский процесс, тогда зомби умрет вместе с ним. Если есть желание, можете почитать про организацию процессов: http://cad.narod.ru/methods/os_unix/unibas/process.htmlhttp://linux-admin.net.ru/content/257А вообще, можете поискать в Google-Linux.
|
|
|
|
|
Jan 24 2007, 16:48
|
Местный
  
Группа: Свой
Сообщений: 351
Регистрация: 11-09-05
Из: Харьков
Пользователь №: 8 458

|
Цитата(snedelko @ Jan 23 2007, 12:13)  А если процесс зомби, то потоки, запущенные им, тоже зомби? И вообще, тонкостей тут куча, где бы про это подробно почитать ? Вопрос в общих контурах - понятный и описанный, а в деталях - заинтересовал... Я тут набросал тест маленький, на скорую руку, который позволяет создавать "временных зомби", наблюдать их... (пример очень draft - писался на коленке - no comments): Код #include <signal.h> #include <iostream>
using std::cout; using std::endl; using std::flush;
static const int MSG_BUF = 160; static char msgbuf[ MSG_BUF ]; static char *puthead( void ) { struct timespec t; clock_gettime( CLOCK_REALTIME, &t ); int sec = t.tv_sec % 60, min = t.tv_sec % 3600 / 60, ms = t.tv_nsec / 1000000, mks = t.tv_nsec % 1000000 / 1000; sprintf( msgbuf, "[%02d:%02d.%03d.%03d] %d: ", min, sec, ms, mks, getpid() ); return msgbuf + strlen( msgbuf ); };
static void chend( int ) { sprintf( puthead(), "oh, my God - my child is dead!\n" ); cout << msgbuf << flush; };
int main( int argc, char* argv[] ) { int c, msec = 300, level = 0; while( ( c = getopt( argc, argv, "c:t:" ) ) != -1 ) { switch( c ) { case 'c': level = atoi( optarg ); break; case 't': msec = atoi( optarg ); break; default : exit( EXIT_FAILURE ); }; }; signal( SIGCHLD, chend ); pid_t id; // = -1; int w = 4, j = -1; while( --level > 0 && ( id = fork() ) == 0 ) { w += j; j = ( j < 0 ? 2 : -1 ); }; sprintf( puthead(), "start - my parent is %d\n", getppid() ); cout << msgbuf << flush; for( int i = 0; i < w; i++ ) if( delay( msec ) != 0 ) --i; else { sprintf( puthead(), "continue %d - parent is %d\n", i + 1 , getppid() ); cout << msgbuf << flush; }; sprintf( puthead(), "finished\n" ); cout << msgbuf << flush; exit( EXIT_SUCCESS ); }; а вот вариант его прогона: Код # ./zomby2 -c4 -t2000 [38:04.744.723] 6467647: start - my parent is 4710443 [38:04.746.723] 6471744: start - my parent is 6467647 [38:04.748.722] 6471745: start - my parent is 6471744 [38:04.748.722] 6471746: start - my parent is 6471745 [38:06.746.417] 6467647: continue 1 - parent is 4710443 [38:06.748.416] 6471744: continue 1 - parent is 6467647 [38:06.750.416] 6471745: continue 1 - parent is 6471744 [38:06.750.416] 6471746: continue 1 - parent is 6471745 [38:08.748.110] 6467647: continue 2 - parent is 4710443 [38:08.750.110] 6471744: continue 2 - parent is 6467647 [38:08.752.110] 6471745: continue 2 - parent is 6471744 [38:08.752.110] 6471746: continue 2 - parent is 6471745 [38:10.749.804] 6467647: continue 3 - parent is 4710443 [38:10.751.804] 6471744: continue 3 - parent is 6467647 [38:10.751.804] 6471744: finished [38:10.752.804] 6467647: oh, my God - my child is dead! [38:10.753.804] 6471745: continue 3 - parent is 6471744 [38:10.753.804] 6471746: continue 3 - parent is 6471745 [38:12.754.497] 6467647: continue 4 - parent is 4710443 [38:12.754.497] 6467647: finished [38:12.755.497] 6471745: continue 4 - parent is 6471744 [38:12.755.497] 6471746: continue 4 - parent is 6471745 [38:12.755.497] 6471746: finished [38:12.756.497] 6471745: oh, my God - my child is dead! # [38:14.758.191] 6471745: continue 5 - parent is 1 [38:14.758.191] 6471745: finished
#
# pidin 6467647 1 ./zomby2 10o NANOSLEEP 6471744 (Zombie) 6471745 1 ./zomby2 10o NANOSLEEP 6471746 1 ./zomby2 10o NANOSLEEP - проганял я, естественно  , не в Linux - но он весь - POSIX: вы можете взять и поганять нечто подобное в вашей любимой ОС - он создаёт любое число процессов, каждый из которых может поочерёдно становиться зомби. P.S. мне особенно понравился  цикл: while( --level > 0 && ( id = fork() ) == 0 ) { w += j; j = ( j < 0 ? 2 : -1 ); }; - который циклом и не является ("... не верь глазам своим"(с) К.Прутков), и в каждом процессе выполняется по 1-й итерации этого "якобы цикла" ровно по 1-му разу : "цикл между процессами"
|
|
|
|
|
Jan 29 2007, 16:41
|
Участник

Группа: Новичок
Сообщений: 44
Регистрация: 10-10-06
Пользователь №: 21 161

|
Цитата(Olej @ Jan 22 2007, 10:20)  Цитата(snedelko @ Jan 22 2007, 11:50)  Вообще, с процессами зомби немного знаком - боролся я с ними, вызывая в обработчике SIGCHLD функцию wait(). В моей ситуации родителем кто является? Скрипт? Объясните пожалуйста. Если скрипт - то есть ли команда - аналог функции wait()? И подскажите мне вот в чем: мой скрипт срабатывает около 3-х раз (в ситуации, когда программа завершается сама (по exit)), а на 4-й раз появляются зомби. Откуда? И почему не появлялись раньше? А вот когда программа завершается по segmentation fault (то бишь её рубит Линукс, тем же kill наверно), то зомби появляються СРАЗУ....
Я мало что понял из этого объяснения  ... Скрипт не может быть родителем  - родителем может быть только породивший процесс, это может быть, например, скриптовый интерпретатор, выполняющий ваш скрипт... P.S. предложение-подсказка - как разобраться в вашей trouble: - сделайте над своим процессом пустую "обёртку", которая будет только exec/spawn ваш процесс... - в ней вы можете перехватывать - наблюдать - обрабатывать все события... - разобравшись что происходит - выбросите обёртку  . Я б именно так и поступил. Как перехватывать/наблюдать/обрабатывать сигналы неплохо описано тут
--------------------
Some days you eat the bear. Some days the bear eats you.
|
|
|
|
|
Jan 30 2007, 06:59
|
Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 8-03-05
Пользователь №: 3 146

|
Может не в тему, но у меня нормально получалось следить, перезапускать процессы из perl, типа foreach $pid(@processes){ if(waitpid($pid,WNOHANG)){ это я к тому, что дспетчер можно и на C написать, но скриптом быстрее, прблем меньше, ИМХО. ЗЫ: пример, буквально за 3 минуты Код #! /usr/bin/perl -w
use strict; use POSIX;
my $proc; my @program = ("wget","-c","-t","1","-T","10", "http://download.xilinx.com/direct/webpack/91/WebPACK_SFD_91i.zip");
unless($proc = fork()){ exec(@program); }
for(;;){ if(waitpid($proc,WNOHANG)){ if($? != 0){ unless($proc = fork()){ exec(@program); } } } select(undef,undef,undef,0.1); } wget просто так, ничего в голову не пришло
Сообщение отредактировал 733259 - Jan 30 2007, 07:34
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|