Кто-то добавил в статью в Википедии "ptrace" , утверждая, что в Linux процесс ptraced сам по себе не может отслеживать другой процесс. Я пытаюсь определить, если (и если да, то почему) это так. Ниже приведена простая программа, которую я разработал, чтобы проверить это. Моя программа не работает (подпроцесс не работает должным образом), но я вполне уверен, что это моя ошибка, а не что-то фундаментальное.
По сути, первоначальный процесс A разветвляется процесс B , который в свою очередь разветвляется C . A отслеживает своего потомка B , B отслеживает своего потомка C . Как только они настроены, все три процесса записываются так, чтобы просто печатать A
, B
или C
в стандартный вывод раз в секунду.
На практике получается, что A и B работают нормально, но C печатает только один раз, а затем застревает. Проверка с помощью ps -eo pid,cmd,wchan
показывает C , застрявшую в функции ядра ptrace_stop
, а остальные находятся в hrtimer_nanosleep
, где я ожидаю, что все три будут.
Очень редко все трое работают (поэтому программа печатает Cs, а также As и Bs), что наводит меня на мысль, что в начальной настройке есть какое-то состояние гонки.
Мои догадываются о том, что может быть не так:
- что-то делать с A , видя
SIGCHLD
, относящееся к B , видя SIGCHLD
, имеющего отношение к сигналу C , и ждать ( 2) сообщать обоим как о B (но хакерский вызов PTRACE_CONT для обоих пидов не исправляет ситуацию)?
- C должен быть выведен как B - имеет C унаследовал ptrace вместо A (и B вызов ptrace не ошибся и не переписал это)?
Кто-нибудь может понять, что я делаю не так? Спасибо.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
static void a(){
while(1){
printf ("A\n");
fflush(stdout);
sleep(1);
}
}
static void b(){
while(1){
printf ("B\n");
fflush(stdout);
sleep(1);
}
}
static void c(){
while(1){
printf ("C\n");
fflush(stdout);
sleep(1);
}
}
static void sigchld_handler(int sig){
int result;
pid_t child_pid = wait(NULL); // find who send us this SIGCHLD
printf("SIGCHLD on %d\n", child_pid);
result=ptrace(PTRACE_CONT, child_pid, sig, NULL);
if(result) {
perror("continuing after SIGCHLD");
}
}
int main(int argc,
char **argv){
pid_t mychild_pid;
int result;
printf("pidA = %d\n", getpid());
signal(SIGCHLD, sigchld_handler);
mychild_pid = fork();
if (mychild_pid) {
printf("pidB = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("outer ptrace");
}
a();
}
else {
mychild_pid = fork();
if (mychild_pid) {
printf("pidC = %d\n", mychild_pid);
result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
if(result==-1){
perror("inner ptrace");
}
b();
}
else {
c();
}
}
return 0;
}