Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2034289
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类: LINUX

2006-04-22 12:37:17

背景:
在有的情况下我们不得不监视一个已经运行的进程的结束,比如说在睡觉之前我想升级我的Gentoo系统,所以我运行了emerge -aDNtuv world,可是在我想睡觉的时候发现升级还没有完成,当然这和我事先对时间估计不足有关,为了节省电能,我不得不监视进程的结束,然后运行shutdown -h now命令。如果不这样,直接打断进程的执行,将会更加麻烦。比较普遍的做法是,自己写一个脚本监视进程的结束,如下:
while : ; do
        ps -C $prog &> /dev/null
        if [ $? -ne 0 ]; then
                break;
        fi
        echo $prog is running! try it 5 minutes later!
        sleep 300
done
基本要求实现了,但现在有两个问题:
  1. 用轮询的方式效率不高,浪费系统资源。
  2. 不能够及时的发现进程的终止,精度不够高。
所以需要一种机制,能够实时获得已运行进程的结束。
ptrace:
ptrace是内核为调试程序留的系统调试接口,gdb,strace都是用这个系统调用实现的。ptrace不仅能够跟踪调试进程的子进程,还能attach到一个正在运行的进程上,进程实时监控。当ptrace请求attach到一个进程时,kernel先进程权限的检查,如果权限允许,那么attach成功,被attach的进程在形式上将成为执行attach调用的子进程。其效果和执行了PTRACE_TRACEME的效果一样,当其接收到除SIGKILL外的任何信号时,他将向监视进程发送SIGCHLD信号报告自己收到了信号,然后停止运行等待监视进程做出决策,监视进程可以用信号SIGCHLD的信号处理函数和wait调用得到这个Notify,然后决策!另外当其执行类似exec的系统调用转而执行别的命令的时候,如果监视进程想要,它会向监视进程传递SIGTRAP信号。
实现:
我们可应用ptrace实现我们的目的。具体代码如下:

#include
#include
#include
#include
#include
#include
#include

static int sig_received = 0;

void sig_handler(int signo)
{
        sig_received = 1;
}

int main(int argc, char *argv[])
{
        pid_t ret;
        pid_t child;
        int i;

        if(argc != 2){
                fprintf(stderr, "Usage: %s pid\n", argv[0]);
                exit(1);
        }
        signal(SIGCHLD, sig_handler);

        /* check the parameter */
        for(i = 0; argv[1][i] >= '0' && argv[1][i] <= '9'; i ++) ;
        if(argv[1][i] != '\0'){
                fprintf(stderr, "Usage: %s pid\n", argv[0]);
                exit(1);
        }
        child = atoi(argv[1]);

        if(ptrace(PTRACE_ATTACH, child, NULL, NULL) == -1){
                perror("ptrace");
                exit(1);
        }
        while(1){
                if(sig_received){
                        /* check if the process exists */
                        ret = waitpid(child, NULL, WNOHANG);
                        if(ret == -1){
                                if(errno ==  ECHILD){ /* the child has exit */
                                        return 0;
                                }
                                perror("waitpid");
                                exit(1);
                        }
                        /* child is running, let it continue */
                        sig_received = 0; /* must before ptrace */
                        if(ptrace(PTRACE_CONT, child, NULL, SIGCHLD) == -1){
                                perror("ptrace");
                                exit(1);
                        }
                }
                ret = wait(NULL); /* wait a signal */
                if(ret == -1){
                        if(errno == EINTR) continue;
                        perror("wait");
                        exit(1);
                }else{
                        continue; /* received signal from the child */
                }
        }

        return 0;
}
局限性:
  1. 不能监视没有attach权限的进程。
  2. 如果被监视进程中有很多信号出现的话,可能会导致其执行效率下降。
总结:
这里只是给出了ptrace调用在等待一个进程退出时的应用,开动脑筋,应该还能应用于其它非父子关系的进程间通信!
阅读(1762) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~