有人在维基百科上写了一篇文章"ptrace",声称在Linux上,一个ptraced进程本身无法启动另一个进程.我试图确定是否(以及如果是这样的原因)就是这种情况.下面是一个我试图测试的简单程序.我的程序失败(子子进程无法正常运行)但我确信这是我的错误,而不是基本的东西.
在本质上是初始过程甲叉过程乙这反过来叉Ç.一个 ptraces其子乙,乙 ptraces其子Ç.一旦完成设置后,所有三个过程被写入只是打印A
,B
或C
到标准输出每秒一次.
在实践中发生的事情是A和B工作正常,但C只打印一次然后卡住.检查ps -eo pid,cmd,wchan
显示C卡在内核函数中,ptrace_stop
而其余的都在hrtimer_nanosleep
我希望所有三个都在的位置.
偶尔三个都可以工作(所以程序打印Cs以及As和Bs),这让我相信初始设置中存在一些竞争条件.
我猜测可能出现的问题是:
SIGCHLD
相关的B看到SIGCHLD
一个信号,做ç,并等待(2)报告既从未来乙(但PTRACE_CONT的双方的PID哈克调用不解决的事情)?谁能弄清楚我做错了什么?谢谢.
#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;
}
Run Code Online (Sandbox Code Playgroud)
你确实看到了竞争条件.您可以通过sleep(1);
在第二次 fork()
呼叫之前立即重复发生它.
由于进程A未正确地将信号传递给进程B,因此导致竞争条件.这意味着如果进程B在进程A开始跟踪进程B之后开始跟踪进程C,则进程B永远不会获得SIGCHLD
指示进程C已停止的信号,所以它永远不会继续下去.
要解决此问题,您只需修复SIGCHLD
处理程序:
static void sigchld_handler(int sig){
int result, status;
pid_t child_pid = wait(&status); // find who send us this SIGCHLD
printf("%d received SIGCHLD on %d\n", getpid(), child_pid);
if (WIFSTOPPED(status))
{
result=ptrace(PTRACE_CONT, child_pid, 0, WSTOPSIG(status));
if(result) {
perror("continuing after SIGCHLD");
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1657 次 |
最近记录: |