LINUX.ORG.RU

fork и execve - странности поведения


0

0

Итак, запускается прога p1
Здесь и далее запись вида %i(%i) означает pid(ppid)

p1 101(80)
|
|-----fork->--------------+
| |
+>-p1-main (sleep(1000); |
|
+-<----p1-child----<------+
|
execve ("p2", .......);
|
V
p2 102(101)
|
|->--fork---->------------|
| |
+>-p2-main (return 0); |
|
p2-child--103(1)----<-----+



Допустим p1 101(80)
Прога форкается и имеем p1-main 101(80) и p1-child 102(101)
p1-main вешается в длинный слип и ни кому не мешает
p1-child делает execve, запуская тем самым прогу p2 102(101)
То бишь пид и ппид сохраняются, как по-моему man-разумению
и должно быть
p2 тоже форкается и тут начинается самое интересное

Первое: p2-main 102(101) прощается с нами и делает return 0
По идее должна завершиться, но на самом деле она уходит в зомби и остаётся висеть, пока p1-main
не окончится (кончится слип p1-main или придёт какой-нить SIGINT) и исчезает вместе с ним

Второе: p2-child почему-то имеет значения 103(1), то бишь
имеет предком не p2-main, а init.

Вопросы:
1. Почему зомбируется p2-main и так зависит от предка
p1-main, с которым связь аж через execve(замещение всех данных)?
2. С какого х.... ппид для p2-child не 102, а 1 ?

Интересующимся могу выслать маленькие дебаг-сырцы для p1 и p2.


p1 101(80)
|
|-----fork->------------------+
|.....................................|
+>-p1-main (sleep(1000);..|
......................................|
+-<----p1-child----<--------+
|
execve ("p2", .......);
|
V
p2 102(101)
|
|->--fork---->---------------|
|...................................|
+>-p2-main (return 0);....|
....................................|
p2-child--103(1)----<-----+

Ant0
() автор топика
Ответ на: комментарий от Ant0

это сырец p1
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>

int main(int argc, char *argv[])
{
  pid_t pid;
  int i;

  printf("I'm httpd %i(%i)\n",(int)getpid(),(int)getppid());
  printf("and i'm starting child for execve, which pid is...\n");
  pid=fork();
  if (pid<0) {perror("fuck, httpd fork breaked down!!!"); return -errno;}
  if (pid)
    {
      printf("%i. Now httpd goes to very long sleep. Good dreams!!!\n",(int)pid);
      sleep(10000);
      printf("Now httpd goes to exit. Buy!!!\n");
      return 0;
	}
  //child/
  sleep(5);
  printf("Hi, I'm httpd child for execve %i(%i) after 5 sec sleep\n",getpid(),getppid());
  printf("Will do execve after 20 sec\n");
  for (i=30; i>0; i--) {
	  printf("(x)%2i ",i);
	  fflush(stdout);
	  sleep(1);
  }
  printf("Now do execve\n");
  execl("/tmp/cgi","/tmp/cgi",NULL);
  perror("(httpd child): FUCK!!! execle dropped");
  return -errno;
}

это сырец p2
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>

int main()
{
  pid_t pid;
  int i;
  
  printf("Hello, I'm cgi proga %i(%i)\n",getpid(),getppid());
  printf("(cgi) Now I'm starting new fork and going to exit...\n");
  pid=fork();
  if (pid<0) {perror("(cgi)Fuck!!! fork dropped!!!"); return -errno;}
  if (pid)
    {
      printf("(cgi %i(%i)) My child pid is %i. I'm exiting... Buy!!!\n",getpid(),getppid(),pid);
      return 0;
    }
  sleep(5);
  printf("Hi. I'm cgi fork %i(%i) after 5 sec sleep\n",(int)getpid(),(int)getppid());
  printf("(end) going to death\n");
  for (i=240; i>0; i--)
    {
      if (!i%10) printf("\n");
      printf("(end)%2i ",i);
      fflush(stdout);
      sleep(1);
    }
  printf("(end) Buy!\n");
  return 0;  
}

Ant0
() автор топика
Ответ на: комментарий от Ant0

2Ant0:

Прочитай какую-нибудь книжку пр Юникс, в 2 словах трудно основы доходчиво растолковать.

Коротко:

Пока не сделаешь wait() в родителе, дочка до конца не умрет (прозомбируется, если помереть захочет).

Если папа сдох, дочка передается init'у (на этом факте демоны основаны).

Die-Hard ★★★★★
()

А пошел прикол из-за того:
сервер (будь то thttpd или встроенный в басибокс httpd) запускает CGI-шку

мне надо из CGI запустить шеловский дремучий (дооолгий) скрипт
но thttpd прибивает CGI если тот долго работает
можно было бы увеличить таймауты, но дело в том, что пока скрипт шеловский работает не могу ничего послать клиенту - ни перенаправление, ни страничку подсунуть - выглядит буд-то повис сервак (хотя он работаит нормально, шуршит во всю)

ну может кто ответит на другой вопрос: как запустить шеловский скрипт, чтобы он работал в бакграунде..
типа независимого ни от чего форка?

Ant0
() автор топика

и еще небольшое отступление от темы 8) fork годится только для демонов которые обслуживают очень небольшое кол-во сетевых клиентов... на будущее еще покури ка select/poll/epoll ну и fsm...

Ex ★★
()
Ответ на: комментарий от Ant0

> как запустить шеловский скрипт, чтобы он работал в бакграунде.. типа независимого ни от чего форка?

Как обычно,

sh script &

Если он как-то общается с вводом-выводом, то так:

sh script >/dev/null 2>&1 </dev/null &

А если хочешь вообще его изолировать от окружающего мира. то можно так:

setsid sh -c ./script >/dev/null 2>&1 </dev/null

Если его запускаешь из программы, то лучше всего дважды форкнуться, переоткрыть дескрипторы 0, 1, 2 на /dev/null, сделать setsid() и запустить exec'ом /bin/sh с аргументами sh -с ./script

Еще взгляни сюда:

http://www.linux.org.ru/view-message.jsp?msgid=245840

Die-Hard ★★★★★
()

Всем отвечавшим огромное спасибо!!!
Разобрался ;)

setsid() мне нужен был :)

ЗЫ Теперь я знаю кунг-фу! ;) (c) из матрицы

Ant0
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.