Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5771992
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2011-07-07 11:50:11

这是blade问的一个问题,一个python脚本会fork出很多子进程一起工作,想能够一种方法同时kill掉这些脚本进程。

因为是python脚本,不能简单通过killall的方式来搞,因为可能还有其他python脚本运行。一种变通的方法就是grep出特定的python脚本执行进程,然后挨个的kill掉,很山寨啊。

能否有些优雅的方式来搞定这个事情呢,忽然想起似乎有api可以设置进程的名字,如果python脚本设置了进程层的名字的话,这样就可以与其他的python脚本进程区分开来了。

注意进程title和进程name是有区别的,通过strace查看ps和killall执行的系统调用,可以看出进程title是通过/proc/$pid/cmdline读取的,进程name通过/proc/$pid/stat读取的。
cmdline记录的是一个程序的启动参数,包括程序名&参数,就是argv[]的内容,如果要修改进程title,也就是要修改进程cmdline,修改进程的argv[],把argv[0]改为需要修改的title,argv[1]设置为NULL。【不考虑title超长的情况】
我们ps aux看到的是进程的title,killall使用的是进程的name,使用ps -e -o pid= -o comm=可以查看全部进程的pid和name。

参数argv和环境变量在连续的存储空间,如果贸然修改argv[0]可能会破坏这部分内存结构,因为title的长度不确定,如果太长了就修改了环境变量的内存区域。解决方案是重新给环境变量申请内存区域,然后将环境变量复制过去(environ是全局变量)。

【后记】ptcrl可以通过PR_SET_PDEATHSIG选项来设置父进程挂掉后向子进程发送XX信号。例如accord中
  1. /* flush on daemon's crash */
  2.                 sa_new.sa_handler = (void*)log_sigsegv;
  3.                 sigemptyset(&sa_new.sa_mask);
  4.                 sa_new.sa_flags = 0;
  5.                 sigaction(SIGSEGV, &sa_new, &sa_old );

  6.                 prctl(PR_SET_PDEATHSIG, SIGSEGV);


示例代码

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/prctl.h>

#ifndef PR_SET_NAME
#define PR_SET_NAME 15
#endif
 
#ifndef PR_GET_NAME
#define PR_GET_NAME 16
#endif
 
static char *arg_start;
static char *arg_end;
static char *env_start;
 
void init_proc_title(int argc, char **argv) {
        int i;
        arg_start = argv[0];
        arg_end = argv[argc-1] + strlen(argv[argc-1])+1;
        env_start = environ[0];
        for(i=0; i<argc; i++)
                argv[i] = strdup(argv[i]);
}
 
void set_proc_title(const char *title) {
    int tlen = strlen(title)+1;
        int i;
        char *p;
 
        if(arg_end-arg_start < tlen && env_start==arg_end) {
            char *env_end = env_start;
            for(i=0; environ[i]; i++) {
                if(env_end == environ[i]) {
                    env_end = environ[i] + strlen(environ[i]) + 1;
                    environ[i] = strdup(environ[i]);
                } else
                    break;
            }
            arg_end = env_end;
            env_start = NULL;
        }
        i = arg_end - arg_start;
        if(tlen==i) {
            strcpy(arg_start, title);
        } else if(tlen < i) {
            strcpy(arg_start, title);
            memset(arg_start+tlen, 0, i-tlen);
        // 1、当要更改的进程名称串比原始进程名称串短时,填充argv[0]字段时,改为填充argv[0]区的后段,前段填充0

        memset(arg_start,0,i);
        strcpy(arg_start + (i - tlen),title);
        } else {
            *(char *)mempcpy(arg_start, title, i-1) = '\0';
        }
        if(env_start) {
            p = strchr(arg_start, ' ');
            if(p) *p = '\0';
        }
}

void set_proc_name(const char *name) {
        prctl(PR_SET_NAME, name);
}
 
void get_proc_name(char *name) {
        prctl(PR_GET_NAME, name);
}

int main(int argc, char *argv[])
{
    int ret = 0;

    pid_t orig_pid = getpid();

    for(int i=0; i<3; i++)
    {
        pid_t pid = fork();
        if(pid==0)
        {
            prctl(PR_SET_PDEATHSIG, SIGHUP);
            break;
        }
    }

    if(getpid()==orig_pid)
    {
        const char *proc_title = "t_title";
        const char *proc_name = "t_name";
        init_proc_title(argc,argv);
        set_proc_title(proc_title);
        set_proc_name (proc_name);
    }

    while(1)
    {
        //printf("In pid: %d\n", getpid());

        sleep(5);
    }
    return 0;
}



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