LINUX.ORG.RU

по поводу man,exec и fork


0

1

Всем привет. Суть вопроса. Вот код:
--------------------------
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stddef.h>


int main()
{
pid_t chpid;
chpid=fork();
if(chpid==0) // child
{
sleep(3);
execlp(«/usr/bin/man»,«/usr/bin/man»,«ps»,NULL);
   
}

}
-------------------
все работает, man даже пытается запуститься, но потом выводит:
/usr/bin/man: command exited with status 1:pager -s

Внимание, вопрос=) В чем проблема? Здесь ключевую роль играет смерть родителя, т.к. если родителя, допустим зациклить, или сделать sleep хотя бы на 5 секунд, то все работает.

Попутный вопрос. В чем заключается роль лидера группы процессов?? Чем группа с лидером отличается от группы без лидера? Перерыл кучу сайтов и книжек, ничего не нашел. Просто в данном случае родитель — лидер группы, и возможно, это имеет принципиальное значение.



P.S. обнаружил замечательную вещь: если прогнать все это дело под strace'ом, то все работает. чудеса... тем, не менее, вопрос открыт=) А то на сдаче задания требуют объяснить, а никто не знает(



Все дело в less. Вот так будет работать:

execlp(«/usr/bin/man»,«man»,«ps»,"-P",«/bin/cat»,NULL);

Видимо less использует какие-то специфические ioctl для работы с терминалом.

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

Хотя на ней действительно нет мануала к ps :)

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

Спасибо за ссылку.Но тогда непонятно, почему, если, скажем, заменить exec на printf(«still alive»); , то вывод в консоль идет. Дочерние процессы здесь не убиваются. В чем принципиальное отличие мана от принтфа? Может, дело в том, что ман требует еще и ввод?

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

Поставь wait() в конце main() и всё у тебя заработает. Надеюсь, ты понял, в чём у тебя ошибка? ж)

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

Да нет, понятно, что с wait'ом работает=) Понятно почему. Непонятно, почему без wait'а не пашет. Еще раз: мои программы (там всего лишь wait и printf) после смерти родителя ПРОДОЛЖАЮТ ВЫВОД в консоль. Man этого сделать НЕ МОЖЕТ. В чем принципиальное различие?

Спасибо)

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

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

anonymous
()
Ответ на: комментарий от DimG

Возьми strace и посмотри

strace less /etc/fstab 2> /tmp/log &

open(«/dev/tty», O_RDONLY|O_LARGEFILE) = 6
ioctl(6, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
fsync(6) = -1 EINVAL (Invalid argument)
ioctl(6, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = ? ERESTARTSYS (To be restarted)
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
ioctl(6, SNDCTL_TMR_STOP or TCSETSW, {B38400 opost isig -icanon -echo ...}) = ? ERESTARTSYS (To be restarted)
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---
--- SIGTTOU (Stopped (tty output)) @ 0 (0) ---

anonymous
()
Ответ на: Возьми strace и посмотри от anonymous

Спасибо. Это значит, что процесс теряет контролирующий терминал, так? Между тем выяснилось, что процесс — дите после смерти родителя остается в той же группе, т.е. потерять он его не может.

Кроме того, если прогнать под strace'ом всю программу (мою) и вывести все это дело в файл (strace -f ./a.out > temp.txt) то в файлике красуется нормальный man. Как вы это объясните?

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

тем что ман видит, что вывод не на терминал, а в пайп и не пытается запустить пейджер (less/more/etc) а просто выплевывает все в stdout).

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

Спасибо за ответ. Итак, в первоначальном варианте man получает SIGTTOU. Следовательно он потерял терминал. А теперь, внимание, вопрос: почему?? SIGHUP'ом там и не пахнет.

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

ну поменяй вызов с man на вот такой execlp(«/usr/bin/strace»,«/usr/bin/strace»,"-o/tmp/log",«man»,«ps»,NULL); и посмотри, что в логе.

maloi ★★★★★
()

я только мельком глянул, может чего упустил.

но, скорее всего, кто-то из children пытается работать
с /dev/tty и read/ioctl получает EIO. или даже SIGHUP,
в зависимости от того, что там делается.

происходит это потому, что после смерти родителя все
children уже не в foreground (TIOCSPGRP).

если прогнать все это дело под strace'ом, то все работает.


конечно. ведь при этом сам strace является лидером группы
(забыл, как это правильно называется, и не путать с
session leader). и он ведь не завершается.

если strace свежий, у него есть недокументированный ключ -D.
с этим ключиком strace будет (упрощенно) daeminized, а tracee
сохранит «правильный» parent (в данном случае bash).

google: job control, orphaned pgrp

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

Проблема в том, что после смерти родителя ребенок не меняет номера группы — а значит нет никакого повода к потере управляющего терминала, разве нет? По поводу осиротевшей группы — SIGHUP так же не высылается — проверялось тестовой прогой, ловящей его. Кроме того, достаточные условия (а именно, блокировка ребенка) не выполнены для SIGHUP'a.

Спасибо за ответ.

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

> смерти родителя ребенок не меняет номера группы

вот именно. а его parent (bash) меняет tty->prgp «назад».
я же написал про TIOCSPGRP.

 — SIGHUP так же не высылается — проверялось


значит, наверное, -EIO. про SIGHUP я упомянул с оговоркой.

но, еще раз. я даже не читал этот тред, и на код толком не
смотрел. так что может я и ошибаюсь.

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

не заметил...

никакого повода к потере управляющего терминала


да он и не «теряется». меняется foreground pgrp
для самого терминала.

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

Все, кажись я понял. Текущая группа действительно меняется. Меняется на группу bash'а.В связи с этим вопрос: когда (в каких случаях) вызывается функция смены текущей группы и связано ли это как-нибудь с orphaned group?Или это независимые понятие в принципе? Еще вопрос: кем она вызывается в данном случае? В мане написано, что ее может вызывать текущий процесс(читай, процесс, имеющий терминал), но в моем случае bash не является текущим. Или лидер сеанса всегда может распоряжаться терминалом?

Большое спасибо, я, наконец-то начал что-то понимать=)

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

> когда (в каких случаях) вызывается функция смены текущей группы

в данном случае, это делает shell. перед собственно
запуском команды он делает setpgid() + TIOCSPGRP.
когда команда завершается, он снова делает TIOCSPGRP
на себя.

связано ли это как-нибудь с orphaned group?


оххх... и да, и нет. мутная это тема. в данном случае,
скорее нет.

давайте я простой пример приведу:

$ perl -le 'fork && exit; sleep 1; <> || print «read fail: $!»'
$ read fail: Input/output error

если же запускать с strace -f, то

$ strace -f perl -le 'fork && exit; sleep 1; <> || print «read fail: $!»'
...
read(0,

(висит, ожидая ввода)

но strace/ptrace тут не прм чем. просто, с точки зрения shell,
команда не завершается. чтобы достичь того же эффекта, мы можем
сделать

$ perl -le 'fork && exit wait; sleep 1; <> || print «read fail: $!»'

никакого EIO.

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