Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1734851
  • 博文数量: 107
  • 博客积分: 1715
  • 博客等级: 上尉
  • 技术积分: 3168
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-18 18:42
个人简介

阿里巴巴DBA,原去哪儿网DBA。专注于MySQL源码研究、DBA运维、CGroup虚拟化及Linux Kernel源码研究等。 github:https://github.com/HengWang/ Email:king_wangheng@163.com 微博 :@王恒-Henry QQ :506437736

文章分类

全部博文(107)

文章存档

2014年(2)

2013年(38)

2012年(67)

分类: 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:

 

阅读(3664) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~