2014-10-27 91 views
1

我有以下简单的程序,为STDIN设置主程序的pgid和pgroup。然后,我有一个信号处理程序,它可以打印当前进程的pgid以及发送信号的进程的pgid。这里是我的代码pgid在信号处理程序是不同于真正的pgid

pid_t pid; 

void handler(int signum, siginfo_t* siginfo, void* context){ 
    printf("pgid is %d, shell_pgid is %d \n", getpgid(siginfo->si_pid), pid); 
} 


int main() 
{ 
    struct sigaction sa; 


    sa.sa_handler = handler; 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_RESTART; 

    sigaction(SIGINT, &sa, NULL); 

    pid = getpid(); 
    setpgid(pid, pid); 
    tcsetpgrp(STDIN_FILENO, pid); 


     while(1){ 

     } 
} 

然而,当我按下^ C,输出我得到的是

^Cpgid is 335, shell_pgid is 3924 

难道他们不应该因为该程序是在主程序运行的是相同的,信号也是从同一个信号源发出的?

+0

。是''setpgid()'调用成功吗? – abligh 2014-10-27 17:42:16

+0

@abligh是的它确实 – Mariska 2014-10-27 18:48:59

回答

2

我想你可能对过程组ID的工作方式有些困惑。

首先,我收拾你的源:

#define _GNU_SOURCE 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <signal.h> 
#include <string.h> 

pid_t pid; 

void 
handler (int signum, siginfo_t * siginfo, void *context) 
{ 
    printf ("in signal handler pid is %d, getpgid(pid) is %d \n", 
      pid, getpgid (pid)); 
    printf 
    ("in signal handler siginfo->si_pid is %d, getpgid(siginfo->si_pid) is %d \n", 
    siginfo->si_pid, getpgid (siginfo->si_pid)); 
    exit (0); 
} 


int 
main (int argc, char **argv) 
{ 
    struct sigaction sa; 

    memset (&sa, 0, sizeof (sa)); 
    sa.sa_sigaction = handler; 
    sigemptyset (&sa.sa_mask); 
    sa.sa_flags = SA_RESTART | SA_SIGINFO; 

    sigaction (SIGINT, &sa, NULL); 

    pid = getpid(); 
    printf ("before call pgid is %d pid=%d\n", getpgid (pid), pid); 
    setpgid (pid, pid); 
    printf ("after setpgid call pgid is %d pid=%d\n", getpgid (pid), pid); 
    tcsetpgrp (STDIN_FILENO, pid); 
    printf ("after tcsetprgrp call pgid is %d pid=%d\n", getpgid (pid), pid); 

    while (1) 
    { 
    } 
} 

主要的变化是,如果您的处理程序有三个参数,你需要使用SA_SIGINFOsa_sigactionsa_handler指定处理。没有这个,你的处理程序可能会变得无效的第二和第三个参数。

接下来,我修复了您的处理程序,以便打印出si_pid以及pid

我也进行了一些额外的调试。

这是当我从外壳直跑会发生什么:

$ ./x 
before call pgid is 15136 pid=15136 
after setpgid call pgid is 15136 pid=15136 
after tcsetprgrp call pgid is 15136 pid=15136 
^Cin signal handler pid is 15136, getpgid(pid) is 15136 
in signal handler siginfo->si_pid is 0, getpgid(siginfo->si_pid) is 15136 

注意siginfo->si_pid报告为0,因为si_pid只能通过kill发出的信号填写。这意味着0传递给getpgid(),它返回调用进程的PGID,这与前一行返回的getpgid(pid)相同。

下面是如果我从另一个进程中使用kill -SIGINT而不是按^C来杀死它,会发生什么情况。

$ ./x 
before call pgid is 15165 pid=15165 
after setpgid call pgid is 15165 pid=15165 
after tcsetprgrp call pgid is 15165 pid=15165 
in signal handler pid is 15165, getpgid(pid) is 15165 
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858 

正如您所看到的最后一行报告发送kill的进程的PID。

在上述两个示例中,当进程启动时,PGID已经等于PID。这是为什么?那么,我们从命令行启动了一个命令,因此只有一个进程组,所以PGID总是会是PID

那么如果我们启动一个流程组,那么我们不是第一个流程会发生什么?试试这个:

$ echo | ./x 
before call pgid is 15173 pid=15174 
after setpgid call pgid is 15174 pid=15174 
after tcsetprgrp call pgid is 15174 pid=15174 
in signal handler pid is 15174, getpgid(pid) is 15174 
in signal handler siginfo->si_pid is 14858, getpgid(siginfo->si_pid) is 14858 

注意这一个我曾与kill -SIGINT杀死,因为^C去这是(在PGID变更后)的过程组只echo。因此,输入的PGID15173(PID为echo),但被更改为15174(按照您的要求)。

我认为这一切都按预期工作。

我认为你的问题本质上是在你的信号处理程序中。首先,你似乎在期待si_pid来填写。其次,你printf说你要打印pgidshell_pgid(二PGID S,而实际上要打印的过程中发出的击杀PGID(或getpgid(0)如果没有结果这是调用进程的PGID),则进程的PID - 即两个方向错误和PIDPGID同时我也怀疑设立处理程序错误可能会给你一个垃圾第二个参数反正

+0

+1,很好的解释bro – 2014-10-27 20:23:38

+0

@abligh我跑你的程序并在主中死亡,但我的输出是 221:SRC frabi $ ./getpgid 之前调用PGID是4758 PID = 4758 setpgid通话PGID后是4758 PID = 4758 后tcsetprgrp呼叫PGID是4758 PID = 4758 ^ CIN信号处理器的PID为4758,getpgid( pid)在信号处理程序中是4758 siginfo-> si_pid是335,getpgid(siginfo-> si_pid)是335 – Mariska 2014-10-27 21:13:36

+0

是的,所以你直接从shell启动,所以在你启动你之前,'PGID'和'PID'已经相等。看起来当你杀了它,你正在得到一个'si_pid'集合。这可能取决于你的'^ C'处理是如何完成的。我通过'ssh'登录。无论如何,我认为335是你的shell的PID。 – abligh 2014-10-27 23:56:53