Здравствуйте уважаемые Линуксоиды!Я тут решил написать некое подобие командного интерпретатора на Си.
Хотелось бы узнать, как следует запускать процесс в фоновом режиме?
В обычном режиме понятно: fork(), exec() и ждем пока потомок завершится,
а тут как?Буду благодарен любой помощи.
С наилучшими пожеланиями, Ivan
>Здравствуйте уважаемые Линуксоиды!
>
> Я тут решил написать некое подобие командного интерпретатора на Си.
>
>Хотелось бы узнать, как следует запускать процесс в фоновом режиме?
>В обычном режиме понятно: fork(), exec() и ждем пока потомок завершится,
>а тут как?Проше всего:
1. Процесс делает fork и ждет завершения
2. Ребенок делает fork и завершается
3. Внук делает exec>Буду благодарен любой помощи.
>
>С наилучшими пожеланиями, Ivan
А зачем такие сложности ? Если фоновый режим (аналог "$cmd &"), то:1. процесс делает fork и забывает о потомке :)
2. потомок делает execДля правильной реализации завершения потомков нужно перехватить сигнал SIGCHLD на свой обработчик (шоб мог орать "процесс PID завершен") либо направить его на SIG_IGN. Кажись так звучат константы.
Если с ожиданием завершения (аналог "$cmd"), то:1. процесс делает fork и делает wait(pid_потомка)
2. потомок делает exec
>А зачем такие сложности ? Если фоновый режим (аналог "$cmd &"), то:
>
>
>1. процесс делает fork и забывает о потомке :)
>2. потомок делает exec
>
>Для правильной реализации завершения потомков нужно перехватить сигнал SIGCHLD на свой обработчик
>(шоб мог орать "процесс PID завершен") либо направить его на SIG_IGN.У нас, похоже, разное представление о простоте. Неправильно написаный
обработчик (а ошибиться в нем -- как два байта переслать) приведет сами
знаете к чему.Единственным основанием к установке обработчика является необходимость
получать и обрабатывать код завершения процесса, что при фоновом запуске
редко случается.Применение SIG_IGN к SIGCHLD по (не)счастливой случайности работает с
нынешними версиями ядра линукс, но закладываться на это не стоит. POSIX
объявляет результат неопределенным (см. http://www.faqs.org/faqs/unix-faq/faq/part3/section-13.html).Вот, собственно, и все о простоте.
>Кажись так звучат константы.
>Если с ожиданием завершения (аналог "$cmd"), то:
>
>1. процесс делает fork и делает wait(pid_потомка)
>2. потомок делает exec
Так а в схеме:1. Процесс делает fork и ждет завершения
2. Ребенок делает fork и завершается
3. Внук делает execРазве внук потом в зомби не свалится ? Теоретически, он перейдет к родителю, который никаких wait/waitpid делать не будет. После завершения родителя он перейдет к init, который уже все и почистит. То есть, до завершения родителя все его фоновые процессы будут в состоянии зомби. Тоб то, так и так нужно либо на игнорирование вешать сигнал либо на свой обработчик.
Я когда-то давно набросал прозрачный прокси для ньюсов.Там есть обработчик сигнала SIGCHLD. В нем только такая конструкция:
while (waitpid(0,NULL,WNOHANG) == 0);
Вот уже 3-4 года работает :) Система linux-2.2.15pre7, libc6-2.1.3-19
Т.е. это приблизительно так должно выглядеть?for(;;)
{
..
..
if((pid = fork()) <0) {
write(2, "Shell: cannot fork \n",20); exit(1); }else if (pid == 0)
{
if((pid2 = fork()) <0) {
write(2, "Shell: cannot fork\n",20); exit(1); }else if (pid2 == 0) {
execve(path, arg, env);write(2, "Shell: cannot execute\n", 23);
}
else
exit(0);
}
}Что здесь не так?
Запускаем последовательно 2 процесса и после окончания их выполнения видим:1820 pts/5 00:00:00 a.out
1827 pts/5 00:00:00 a.out <defunct>
1828 pts/5 00:00:00 a.out <defunct>Т.е. получается, что фоновые процессы выполнились и остались в состоянии зомби. Теперь нужно как-то завершать эти зомби. Это должен непосредственно сам обработчик SIGCHLD делать?
Ну ты видел мой последний пост ? Там приведен пример обработчика SIGCHLD. И fork у меня один:pid_t pid=fork();
switch (pid) {
case -1: ошибка; break;
case 0: потомок. чего-то даже делает; break;
default: родитель. забыл о потомке;
};
>Так а в схеме:
>
>1. Процесс делает fork и ждет завершения
>2. Ребенок делает fork и завершается
>3. Внук делает exec
>
>Разве внук потом в зомби не свалится ? Теоретически, он перейдет к
>родителю, который никаких wait/waitpid делать не будет. После завершения родителя он
>перейдет к init, который уже все и почистит.Внук сразу перейдет к init. Никаких зомби.
>То есть, до
>завершения родителя все его фоновые процессы будут в состоянии зомби. Тоб
>то, так и так нужно либо на игнорирование вешать сигнал либо
>на свой обработчик.
>
>Я когда-то давно набросал прозрачный прокси для ньюсов.Там есть обработчик сигнала SIGCHLD.
>В нем только такая конструкция:
>
>while (waitpid(0,NULL,WNOHANG) == 0);которая, строго говоря, не делает ничего сверх того, что достигается
двойным fork. Минусы ее описаны в том же faq. Плюсы возникнут, если
будет делаться анализ кодов завершения -- где придется мучительно и
виртуозно обходить множество грабель.>
>Вот уже 3-4 года работает :) Система linux-2.2.15pre7, libc6-2.1.3-19Мои искренние поздравления.