使用waitpid的父进程如何识别终止子进程的信号发送进程?
如何确定发送终止信号给子进程的进程ID?
waitpid() 及其配套的宏(WIFSIGNALED、WTERMSIG等)只能告诉你子进程是被信号终止的,以及具体是哪个信号,但无法直接提供发送该信号的进程ID。要获取这个信息,你可以根据场景选择以下几种方法:
方法1:利用Linux审计机制(无需修改代码)
Linux的audit子系统可以监控系统内的信号发送事件,适合无法修改子进程代码的场景:
- 先确保auditd服务已启动:
systemctl start auditd - 添加监控kill系统调用的规则:
(如果是32位系统,把auditctl -a exit,always -F arch=b64 -S killb64换成b32) - 当子进程被信号终止后,用ausearch查询审计日志:
日志里会包含ausearch -i -sc killsender_pid(发送信号的进程ID)和target_pid(被信号终止的进程ID),你可以通过target_pid匹配你的子进程,从而找到对应的sender_pid。
方法2:通过ptrace跟踪子进程(父进程主动监控)
父进程可以用ptrace跟踪子进程,在子进程收到信号时获取信号的详细信息,包括发送者PID:
- 子进程启动时调用
ptrace(PTRACE_TRACEME, 0, NULL, NULL),让父进程可以跟踪自己; - 父进程调用
waitpid()等待子进程状态变化,当子进程因信号停止时(WIFSTOPPED(status)为真),调用ptrace(PTRACE_GETSIGINFO, pid, NULL, &info)获取信号信息; siginfo_t结构体中的si_pid字段就是发送信号的进程ID。
简单代码示例:
#include <sys/ptrace.h> #include <sys/wait.h> #include <signal.h> #include <stdio.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程:允许父进程跟踪 ptrace(PTRACE_TRACEME, 0, NULL, NULL); // 执行子进程逻辑,比如sleep等待信号 sleep(60); return 0; } else { int status; siginfo_t info; while (waitpid(pid, &status, 0) > 0) { if (WIFEXITED(status)) { printf("子进程正常退出,退出码:%d\n", WEXITSTATUS(status)); break; } else if (WIFSIGNALED(status)) { printf("子进程被信号终止,信号:%d\n", WTERMSIG(status)); break; } else if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); // 获取信号的详细信息,包括发送者PID if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &info) == 0) { printf("子进程收到信号%d,发送者PID:%d\n", sig, info.si_pid); } // 让子进程继续运行(如果不需要暂停) ptrace(PTRACE_CONT, pid, NULL, NULL); } } } return 0; }
注意:ptrace会对子进程的运行性能有轻微影响,且需要父进程有足够权限。
方法3:子进程自定义信号处理(仅适用于可控子进程)
如果子进程是你自己编写的,可以在子进程中捕获可处理的信号,获取发送者PID后通知父进程:
- 在子进程中安装带
siginfo_t参数的信号处理函数(用sigaction,设置SA_SIGINFO标志); - 当收到信号时,从
siginfo_t的si_pid拿到发送者PID,通过管道、套接字等IPC方式发送给父进程; - 父进程读取到信息后,就知道是哪个进程发的信号。
局限性:这种方法无法处理不可捕获/忽略的信号(比如SIGKILL、SIGSTOP),因为这些信号的处理函数无法被触发。
内容的提问来源于stack exchange,提问作者yqq hqq
相关产品推荐
相关产品推荐

