1

我有以下简单的程序,它为 STDIN 设置主程序的 pgid 和 pgroup。然后,我有一个信号处理程序,它打印当前进程的 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 

由于程序在主程序中运行并且信号也是从同一源发送的,因此它们不应该是相同的吗?

4

1 回答 1

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)
    {
    }
}

主要的变化是,如果你的处理程序接受三个参数,你需要在not中使用SA_SIGINFO并指定处理程序。否则,您的处理程序可能会得到无效的第二个和第三个参数。sa_sigactionsa_handler

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

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

这就是我直接从 shell 运行时发生的情况:

$ ./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()which 返回调用进程的 ,这与上一行返回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.

在上述两个示例中,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因为 a^C进入进程组(在PGID更改之后) only echo。因此,PGIDon 条目是15173(的 PID echo),但被更改为15174(根据您的要求)。

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

我认为您遇到的问题本质上在于您的信号处理程序。首先,您似乎期望si_pid被填写。其次,您printf说您正在打印pgidand shell_pgid(两个PGIDs,而实际上您正在打印PGID发出 kill 的进程的 the (或者如果没有,其结果getpgid(0)PGID调用进程的),然后是进程的 PID - 即错误的方式和 aPID和 a PGID。而且我怀疑设置错误的处理程序可能会给你一个垃圾的第二个参数。

于 2014-10-27T20:22:23.523 回答