阿里巴巴DBA,原去哪儿网DBA。专注于MySQL源码研究、DBA运维、CGroup虚拟化及Linux Kernel源码研究等。 github:https://github.com/HengWang/ Email:king_wangheng@163.com 微博 :@王恒-Henry QQ :506437736
分类: Python/Ruby
2013-08-12 19:46:25
在实际应用需求中,需要实时获得某个任务的子进程ID。一般的方式是通过轮询的方式,准实时的获得子进程。为了能够达到完全实时,且尽可能少利用的系统资源,利用ptrace方式实现该功能。
轮询方式实现准实时获取子进程,一般是通过查看/proc/pid/task目录下的子进程或线程ID文件夹。这种方式的不足是只能做到准实时,如果子进程在轮询周期内完成,那么就可能检测不到。并且轮询时效性,依赖于轮询的频率,高频的轮询,会浪费大量的CPU资源,低频的轮询,会带来较大的误差。
为了能够实时检测任务的子进程,通过ptrace的方式,可以在子进程创建阶段,检测到子进程,并获得相应的ID。C语言实现已经由内核组大神@三百 完成,由于本人代码是python脚本,于是参考C实现,利用python_ptrace包,完成python的实时子进程抓取。
在运行该脚本时,需要首先安装python_ptrace包,该包的不足之处是文档太少了,并且使用者也非常少,只能通过代码找一些信息。
代码非常简单,不多解释,具体实现如下所示:
import os import sys import resource from ptrace.binding import (ptrace_syscall,ptrace_attach,ptrace_getregs) from ptrace.syscall import SYSCALL_NAMES # 所有子进程退出或终止的处理逻辑 def wait_status(): status = None pid, status = os.waitpid(-1,0) if os.WIFEXITED(status): print "-- child process was exited." return -1 if os.WIFSIGNALED(status): print "-- child process terminated by a signal." return -1 if os.WCOREDUMP(status): print "-- child process coredump." return -1 if os.WSTOPSIG(status): return 0 return -1 # 跟踪进程,实时获得子进程创建。 def trace(pid): ptrace_attach(pid) if wait_status() == -1: return -1 print "-- start traceing %d ..." %pid
while True: ptrace_syscall(pid) if wait_status() == -1: ptrace_detach(pid) return -1 regs = ptrace_getregs(pid) res = SYSCALL_NAMES.get(regs.orig_rax) if res == "clone" or res == "fork" or res == "vfork" or res == "execve": limit = resource.getrlimit(resource.RLIMIT_NPROC) if regs.rax > 0 and regs.rax < limit[1]: print "create new child: %s" %regs.rax return 0
if __name__ == "__main__": ppid = int(sys.argv[1]) trace(ppid) |
执行时,输入需要定位的进程ID即可,这样就可以不断输出子进程ID信息。这仅仅是一个抓取的案例,在实际应用中,会根据需要将对应的子进程ID进行处理。
1、subprocess_trace:
2、python_ptrace:
3、C语言实现:
4、Sample1:
5、Sample2:
6、Sample3: