Перейти к содержанию
    

Борьба с процессами зомби

Ситуация следующая: есть процесс, который запускается по автозапуску системы. Проблема: процесс при неизвесных обстоятельствах вылетает. Причины: разные java script:emoticon(':)', 'smid_2'). Возможно это утечка памяти, аппаратный сбой (программа работает с драйверами устройств), ошибка при работе с памятью и т. д. Мне нужно отследить "вылетание", и заново запустить программу. Я решил сделать это при помощи скрипта (см. влож. файл), который я поместил в автозапуск (вместо самой программы). Скрипт простой (напомню, что pidof - команда, которая возвращает pid процесса по имени, и если процесса нет, возвращает 0). Все работает, когда программы выходит по exit(0). Но вот при segmentation fault скрипт не помогает, так как процесс становиться зомби (т.е. имеет pid != 0).

 

Подскажите почему, или предложите свой вариант.

smobi.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Известное мне определение процесса зомби - процесс не имеющий родителя (в случае, когда родител мертв, а потомок остался жив). Может посмотреть, жив ли родитель процесса? Если мертв - значит твой процесс - зомби. Кажды процесс, насколько я помню хранит pid родителя.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Известное мне определение процесса зомби - процесс не имеющий родителя (в случае, когда родител мертв, а потомок остался жив). Может посмотреть, жив ли родитель процесса? Если мертв - значит твой процесс - зомби.

Почти так да не совсем:

- зомби - это всегда завершившийся процесс (а не завершившийся родитель) ...

- процесс становится зомби, когда он отправляет по завершению SIGCHLD - а его некому обработать, например процесс родитель просто не обрабатывает его, например, не ожидает завершения на wait() или waitpid()....

- ... можете в запускающем процессе просто добавить пустой обработчик SIGCHLD ;) ...

 

Кажды процесс, насколько я помню хранит pid родителя.

 

pid_t getppid( void );

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, с процессами зомби немного знаком - боролся я с ними, вызывая в обработчике SIGCHLD функцию wait(). В моей ситуации родителем кто является? Скрипт? Объясните пожалуйста. Если скрипт - то есть ли команда - аналог функции wait()?

И подскажите мне вот в чем: мой скрипт срабатывает около 3-х раз (в ситуации, когда программа завершается сама (по exit)), а на 4-й раз появляются зомби. Откуда? И почему не появлялись раньше? А вот когда программа завершается по segmentation fault (то бишь её рубит Линукс, тем же kill наверно), то зомби появляються СРАЗУ....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, с процессами зомби немного знаком - боролся я с ними, вызывая в обработчике SIGCHLD функцию wait(). В моей ситуации родителем кто является? Скрипт? Объясните пожалуйста. Если скрипт - то есть ли команда - аналог функции wait()?

И подскажите мне вот в чем: мой скрипт срабатывает около 3-х раз (в ситуации, когда программа завершается сама (по exit)), а на 4-й раз появляются зомби. Откуда? И почему не появлялись раньше? А вот когда программа завершается по segmentation fault (то бишь её рубит Линукс, тем же kill наверно), то зомби появляються СРАЗУ....

Я мало что понял из этого объяснения :(...

Скрипт не может быть родителем ;) - родителем может быть только породивший процесс, это может быть, например, скриптовый интерпретатор, выполняющий ваш скрипт...

 

P.S. предложение-подсказка - как разобраться в вашей trouble:

- сделайте над своим процессом пустую "обёртку", которая будет только exec/spawn ваш процесс...

- в ней вы можете перехватывать - наблюдать - обрабатывать все события...

- разобравшись что происходит - выбросите обёртку ;).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

- зомби - это всегда завершившийся процесс (а не завершившийся родитель) ...

- процесс становится зомби, когда он отправляет по завершению SIGCHLD - а его некому обработать, например процесс родитель просто не обрабатывает его, например, не ожидает завершения на wait() или waitpid()....

 

А если процесс еще не завершился, а родитель уже откинулся - как ни крути, а процесс уже по любому зомби (его просто некому будет убить по завершению).

Если родитель еще жив и по каким-то причинам не может обработать SIGCHLD - процесс не может считаться зомби, т. к. потенциально родитель еще может его кончить. Интересно, что произойдет с родителем, если он не будет "ждать детей" (wait, waitpid) - он просто заврешиться и все потомки станут зомби. Тонкости, конечно, но все что изложил Olej умещается в моем определении зомби. Или существет пример, когда оно неверно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если процесс зомби, то потоки, запущенные им, тоже зомби? И вообще, тонкостей тут куча, где бы про это подробно почитать ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если процесс зомби, то потоки, запущенные им, тоже зомби? И вообще, тонкостей тут куча, где бы про это подробно почитать ?

 

Вот:

Если же потомок уже завершил работу, а предок не готов принять от системы сигнал об этом событии, то потомок не исчезает полностью, а превращается в "зомби" (zombie)

 

Процесс зомби, следовательно завершил работу и не может принимать сигналы.

Потомки станут зомби, когда завершат свою работу.

 

Вот Вам еще несколько цитат:

 

Если родительский процесс по какой-то причине завершится раньше дочернего, последний становится "сиротой" (orphaned process). "Сироты" автоматически "усыновляются" программой init, выполняющейся в процессе с номером 1, которая и принимает сигнал об их завершении.

 

Если же потомок уже завершил работу, а предок не готов принять от системы сигнал об этом событии, то потомок не исчезает полностью, а превращается в "зомби" (zombie); в поле Stat такие процессы помечаются буквой Z. Зомби не занимает процессорного времени, но строка в таблице процессов остается, и соответствующие структуры ядра не освобождаются. После завершения родительского процесса "осиротевший" зомби на короткое время также становится потомком init, после чего уже "окончательно умирает".

 

Последнее из состояний процесса, достижимых внутренней синхронизацией, есть состояние промежуточного завершения текущего процесса - SZOMB (состояние "зомби"). Состояние "зомби" имеет место, если процесс-потомок завершается по системному вызову exit или по сигналу до планируемой реализации системного вызова wait в процессе-предке. При этом образ завершившегося процесса освобождает адресное пространство, но его дескриптор временно сохраняется в таблице процессов, чтобы обеспечить корректную обработку системного вызова wait в процессе-предке.

 

В состоянии "зомби" процесс не имеет образа в RAM, но информация о нем сохраняется в таблице процессов. Он не поедает ресурсы, но теоретически могут кончится PID'ы.

 

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

 

Если есть желание, можете почитать про организацию процессов:

http://cad.narod.ru/methods/os_unix/unibas/process.html

http://linux-admin.net.ru/content/257

 

А вообще, можете поискать в Google-Linux.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если процесс зомби, то потоки, запущенные им, тоже зомби? И вообще, тонкостей тут куча, где бы про это подробно почитать ?

 

Вопрос в общих контурах - понятный и описанный, а в деталях - заинтересовал...

Я тут набросал тест маленький, на скорую руку, который позволяет создавать "временных зомби", наблюдать их... (пример очень 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-му разу : "цикл между процессами" ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вообще, с процессами зомби немного знаком - боролся я с ними, вызывая в обработчике SIGCHLD функцию wait(). В моей ситуации родителем кто является? Скрипт? Объясните пожалуйста. Если скрипт - то есть ли команда - аналог функции wait()?

И подскажите мне вот в чем: мой скрипт срабатывает около 3-х раз (в ситуации, когда программа завершается сама (по exit)), а на 4-й раз появляются зомби. Откуда? И почему не появлялись раньше? А вот когда программа завершается по segmentation fault (то бишь её рубит Линукс, тем же kill наверно), то зомби появляються СРАЗУ....

Я мало что понял из этого объяснения :(...

Скрипт не может быть родителем ;) - родителем может быть только породивший процесс, это может быть, например, скриптовый интерпретатор, выполняющий ваш скрипт...

 

P.S. предложение-подсказка - как разобраться в вашей trouble:

- сделайте над своим процессом пустую "обёртку", которая будет только exec/spawn ваш процесс...

- в ней вы можете перехватывать - наблюдать - обрабатывать все события...

- разобравшись что происходит - выбросите обёртку ;).

 

Я б именно так и поступил. Как перехватывать/наблюдать/обрабатывать сигналы неплохо описано тут

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Извините нет времени подробно прочитать тему, я взял из бизибокса реализацию ps дальше брал состояние процесса и всё. В /proc оно вроде отображается. Ну а далее запускаем по крону с нужной частотой. Можно сделать чтобы процесс писал что-то в файлик а другая програмка его анализировала или скрипт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может не в тему, но у меня нормально получалось следить, перезапускать процессы из 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

to модератор:

- эту тему, наверное, нужно перенести в подфорум "Программирование" ? :

http://electronix.ru/forum/index.php?showforum=154

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...