Вот такая проблема: на системе с LinuxThreads один из тредов делает
fork(). В это время другой тред, пользуясь известным pid-ом этого треда,
делает связку
ptrace(PTRACE_ATTACH, pid, NULL, NULL)
waitpid(pid, status, __WALL)
ptrace(PTRACE_GETREGS, pid, NIL, ®s)
ptrace(PTRACE_DETACH, pid, NULL, NULL)
Приостановленный тред продолжает работу, но виснет в fork()! В GDB
видно, что тред выполнил int 0x80 - системный вызов произошел. Дальше
ничего нет - fork() повис где-то, видимо, в ядре.
Как же такое может быть?... Что же делать? :(
версия ядра??
что возвращает fork()??
>Приостановленный тред продолжает работу, но виснет в fork()!
ничего не понял. обьясните
>видно, что тред выполнил int 0x80 - системный вызов произошел.
тред не может выполнить fork(). форк выполняется для процесса тоесть для всех тредов сразу.
И ещё ты уверен что делаеш :
ptrace(PTRACE_ATTACH, pid, NULL, NULL)
waitpid(pid, status, __WALL)
ptrace(PTRACE_GETREGS, pid, NIL, ®s)
ptrace(PTRACE_DETACH, pid, NULL, NULL)
ПОСЛЕ возврата из форка???? у тебя там мьютексы стоят или семафоры????
> версия ядра??
2.4.18
> что возвращает fork()??
НЕ -1. Child исправно запускается, а parent виснет, из fork()-а не
выходит.
>>Приостановленный тред продолжает работу, но виснет в fork()!
>ничего не понял. обьясните
Сорри, неточно выразился. Я не знаю, что происходит. Ясно одно (видно
из трейса GDB): тред A пытается сделать fork() - заходит в
libpthread::fork(), что-то там делает, затем заходит в
libc::__libc_fork(), тоже что-то делает, затем случается int 0x80. Всё.
Действия треда A прекращаются, он повис. Между тем child процесс
рожается и начинает свои действия.
В процессе вызова тредом A функции fork() тред B (легковесный просесс
с другим pid-ом, ибо LinuxThreads!) делает связку ptrace-ptrace-waitpid-ptrace,
это совершенно точно. Почему ПОСЛЕ форка? Это происходит ВО ВРЕМЯ
форка...
Небольшое дополнение. Стало понятно, что, видимо, форкающийся процесс,
зайдя в ядерный fork(), не замечает сигнала SIGCONT, который посылает
ему вызов ptrace(PTRACE_DETACH). Если из консоли послать его руками,
то намертво подвисший в форке тред оживает и вся прилада радостно едет
дальше, как будто ничего плохого не происходило.
>В процессе вызова тредом A функции fork() тред B (легковесный просесс
>с другим pid-ом, ибо LinuxThreads!) делает связку >ptrace-ptrace-waitpid-ptrace, это совершенно точно.
>Почему ПОСЛЕ форка? Это происходит ВО ВРЕМЯ форка...
вот мы и розковыряли.
ты в связке ptrace-ptrace-waitpid-ptrace используеш пид ещё не существующего/не созданного процесса. следственно последствия неопределены. прочитай ман на ptrace и не занимайся ерундой
эх... зря ты не читаешь вопрос внимательно. ptrace-ptrace-waitpid-ptrace
делается на pid существующего процесса, т.е. того, __который__ делает
fork! вовсе не child-a, которого еще нет, а именно парента!
Правильно ли я понимаю, что fork делает процесс, а не thread,
и если процесс с двумя нитями внутри сделает fork, то будет два процесса по две нити в каждом?
ерундой ты страдаеш. ты не можешь делать ptrace для одного треда. ты можешь делать ptrace только для всего процесса сразу.
во вторых откудова ты знаеш пид процесса который соответствует потоку который ты пытаешся трассировать. ни одна ф-я не выдаёт его наружу ядра. при создании треда тебе возвращается Thread-ID который в обычно не имеет никакой связи с pid соответствующего ему процесса. причём этот "процесс" существенно отличается от процессов созданных при помощи fork().
отсюдова собственно и все твои грабли: делая ptrace на pid процесса соответсвующего твоему потоку ты фактически пытаешся остановить весь свой процесс тоесть все треды. система тебя не понимает и посылает SIGCONT процессу соответствующему главному треду.
несмотря на допущенные мною неточности ты наверное уразумел безсмысленность всех своих действий
> абсолютно верно.
Это ты что, собственный монолог одобряешь? :)
Ты не въезжаешь, что такое LinuxThreads. LinuxThreads - это реализация
потоков (тредов, нитей, threads, как угодно) на базе т.н. легковесных
процессов, порождённых системным вызовом clone(). В этой реализации
_каждый_ тред имеет собственный pid, т.е., обращаться с каждым тредом
можно как с отдельным процессом, в том числе и делать ptrace() каждого
из них. Узнать этот pid для каждого индивидуального треда очень просто:
достаточно при создании каждого из них делать getpid() и записывать
в глобальную для всех тредов хэш-таблицу или просто в массив.
Мне нужно сделать "очень простую" вещь: тред-монитор должен периодически
асинхронно по отношению к остальным тредам узнавать их контекст. Вот
для этого и делается ptrace(). Зная ThreadID, мы легко достаем из хэша
соответствующий PID и натравляем на данный тред (на самом деле отдельный
процесс, подчёркиваю!) связку вызовов ptrace и waitpid.
Почему при этом виснет ядерный fork() - и только fork()! - я не
понимаю, и наделся узнать у общественности...
>Правильно ли я понимаю, что fork делает процесс, а не thread, и если
>процесс с двумя нитями внутри сделает fork, то будет два процесса по
>две нити в каждом?
Неправильно. Если процесс делает fork(), вне зависимости от того,
сколько в нём тредов, случится ещё ровно один процесс с одним тредом.
"Сдублируется" тот тред, который делал fork().
>>Правильно ли я понимаю, что fork делает процесс, а не thread, и если
>>процесс с двумя нитями внутри сделает fork, то будет два процесса по
>>две нити в каждом?
>Неправильно. Если процесс делает fork(), вне зависимости от того,
>сколько в нём тредов, случится ещё ровно один процесс с одним тредом.
>"Сдублируется" тот тред, который делал fork().
не вводи человека в заблуждение. если так реализован LinuxTreads то это очередной гвоздь в его могилу. все стандарты требуют что дублировались *ВСЕ* треды
>не вводи человека в заблуждение. если так реализован LinuxTreads то это
>очередной гвоздь в его могилу. все стандарты требуют что дублировались
>*ВСЕ* треды
@#$@#$!!! Какие такие стандарты?! Вот стандарты:
http://www.opengroup.org/onlinepubs/009695399/functions/fork.htmlhttp://bama.ua.edu/cgi-bin/man-cgi?fork1+2
POSIX Threads
In applications that use the POSIX threads API rather than
the Solaris threads API ( applications linked with
-lpthread, whether or not linked with -lthread), a call to
fork() is like a call to fork1(), which replicates only the
calling thread. There is no call that forks a child with all
threads and LWPs duplicated in the child.
Note that if a program is linked with both libraries (-
lthread and -lpthread), the POSIX semantic of fork() pre-
vails.
>Ты не въезжаешь, что такое LinuxThreads.
>LinuxThreads - это реализация потоков (тредов, нитей, threads, как >угодно) на базе т.н. легковесных процессов, порождённых системным >вызовом clone().
это мы прошли в школе в третьем класе
>В этой реализации _каждый_ тред имеет собственный pid, т.е., >обращаться с каждым тредом можно как с отдельным процессом, в том >числе и делать ptrace() каждого из них.
идеологически неверно. каждому треду соответствует TID который некоторым образом, известным только ядру, отображается на PID выполняющего его процесса.
>Узнать этот pid для каждого индивидуального треда очень просто:
>достаточно при создании каждого из них делать getpid() и записывать
>в глобальную для всех тредов хэш-таблицу или просто в массив.
ерунда. getpid ВСЕГДА возвращает pid процесса соответствующего главному/основному треду. не поленись разпечатать свою таблицу или массив.
>Мне нужно сделать "очень простую" вещь: тред-монитор должен >периодически асинхронно по отношению к остальным тредам узнавать их >контекст. Вот для этого и делается ptrace().
>Зная ThreadID, мы легко достаем из хэша соответствующий PID и >натравляем на данный тред (на самом деле отдельный процесс, >подчёркиваю!) связку вызовов ptrace и waitpid.
идеологически неверно. в ядре есть закладки на то что никто никогда из юзерспейса ничего не будет делать с pid "легковесных процессов" реализующих треды. следственно ....
>Почему при этом виснет ядерный fork() - и только fork()! - я не
>понимаю, и наделся узнать у общественности...
потому что ты его останавливаеш при помощи ptrace из другого треда.
> это мы прошли в школе в третьем класе
Неужто?.. ;)
> идеологически неверно. каждому треду соответствует TID который
> некоторым образом, известным только ядру, отображается на PID
> выполняющего его процесса.
Не ядру, а библиотеке LinuxThreads. Ядро совершенно не при чём. Плиз,
объясни, что означает "идеологически неверно".
> ерунда. getpid ВСЕГДА возвращает pid процесса соответствующего
> главному/основному треду. не поленись разпечатать свою таблицу или
> массив.
Хм :) Не поленись написать маленький тестик и убедись сам, что в
LinuxThreads каждый тред имеет уникальный pid, - раз уж тебя так волнует
это обсуждение.
> идеологически неверно. в ядре есть закладки на то что никто никогда из
> юзерспейса ничего не будет делать с pid "легковесных процессов"
> реализующих треды. следственно ....
Так что же значит "идеологически неверно"? А ты когда-нибудь работал
с отладчиками в Linux, с тем же GDB, например? Тебя не удивляет, что
они вообще-то работают?
>потому что ты его останавливаеш при помощи ptrace из другого треда.
ptrace(PTRACE_DETACH) посылает ему SIGCONT. По спецификации процесс
должен ожить и перейти в состояние Runnable.
А что возвращает ptrace(PTRACE_DETACH, pid, NULL, NULL) ? До него вообще дело доходит? И еще я не понял, если трассировка асинхронная, то как она попадает именно в вызов fork, а не куда-то еще...
PS: Я думал, что прикладному программисту должно быть наплевать на реализацию тредов, однако вот этот код запашет только на linuxthreads ибо у них pids различны только.
2cvv:
Под strace смотреть вообще говоря гиблое дело. Strace само использует
ptrace для трассировки, ну а ptrace под ptrace - это... :) Ничего не
выйдет, короче говоря. Я пробовал :)
2Chumka:
Ptrace возвращает всегда 0, ошибок нет.
>то как она попадает именно в вызов fork, а не куда-то еще
Дык трассируемый тред может быть где угодно. А, я же не сказал: зависает
всё иногда, очень редко, именно в тех самых случаях, когда волею небес
тред оказывается в форке.
>Я думал, что прикладному программисту должно быть наплевать
Прикладному - согласен, а вот системному...
>однако вот этот код запашет только на linuxthreads ибо у них pids
>различны только.
Безусловно. Однако не составляет никакого труда сделать run-time
детектание, что перед нами именно LinuxThreads и с ним нужно вести
себя соответственно.
cvv:
> все стандарты требуют что дублировались *ВСЕ* треды
нет, такого не может быть никогда ...
jek_:
> which replicates only the calling thread.
??? тоже очень странно. в linux (и мне это кажется
очень правильным) будет просто создан новый процесс,
поток останется жив. это я о ядре говорю, что там
libpthread творит я не знаю, но интересно было бы
узнать, неужели поток завершится ????
по существу вопроса ничего не могу сказать ...
>Думаю единственный выход, обновиться до 2.6 Я сравнил тут 2.6 и 2.4,
Так-то оно так, я бы и не прочь, но что сказать пользователям, сидящим
на glibc 2.2.5?
> Не въезжаю, что вас смущает.
блин, это я второпях 'replicate' прочитал как 'replace',
и решил, что thread делающий fork() должен по стандарту
умереть, что меня удивило чсрезвычайно :_)
Возможно не совсем по теме... Интересует следующий вопрос.
Допустим один из тредов некоторого процесса сделал fork()
можно ли вызывать wait на потомка из другого треда этого же процесса.
На практике насколько я помню сделать это не получалось.
Интересно, стандартизирован ли данный случай в NPTL или нет?