2014-10-27 25 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