通过CTRL-C接收SIGINT时,发送方pid为零

时间:2022-08-02 14:35:49

In my signal handler which is setup via sigaction() using the SA_SIGINFO flag the si_pid member (which stores the sending process ID) of the siginfo_t struct is zero when SIGINT is triggered via CTRL-C

在通过sigaction()设置的信号处理程序中,使用SA_SIGINFO标记siginfo成员(它存储发送进程ID),当通过CTRL-C触发SIGINT时,SIGINT结构的si_pid值为零

Take the following example which uses signalfd() for simplicity in order to demonstrate the "issue":

以下面的例子为例,使用signalfd()来简化,以演示“问题”:

#include <sys/signalfd.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
        sigset_t mask;
        int sfd;
        struct signalfd_siginfo fdsi;
        ssize_t s;

        printf("my process id: %d\n", getpid());

        sigemptyset(&mask);
        sigaddset(&mask, SIGINT);

        /* block signals to avoid default handling */
        if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) {
                perror("sigprocmask");
                return 1;
        }

        sfd = signalfd(-1, &mask, 0);
        if (sfd == -1) {
                perror("signalfd");
                return 1;
        }

        printf("waiting for sigint ...\n");

        /* raise(SIGINT); */

        s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
        if (s != sizeof(struct signalfd_siginfo)) {
                perror("reading from signal fd");
                return 1;
        }

        if (fdsi.ssi_signo != SIGINT) {
                fprintf(stderr, "received unexpected signal %d\n", fdsi.ssi_signo);
                return 1;
        }

        printf("received SIGINT from process %d\n", fdsi.ssi_pid);

        return 0;
}

If you run this program and trigger a kill -INT pid from another tty the output of the program is:

如果您运行这个程序并从另一个tty触发一个kill -INT pid,程序的输出是:

my process id: 23540
waiting for sigint ...
received SIGINT from process 23186

Now, if you press CTRL-C after starting the program the output is:

现在,如果你在启动程序后按CTRL-C输出是:

my process id: 23551
waiting for sigint ...
^Creceived SIGINT from process 0

If I raise SIGINT in the program (by uncommenting the line /* raise(SIGINT); */ in the code sample) the output is:

如果我在程序中提升了SIGINT(通过取消对line /* raise(SIGINT)的注释);*/在代码示例中)输出为:

my process id: 23577
waiting for sigint ...
received SIGINT from process 23577

Now if I enabled the linux ftrace syscall tracers for kill, tkill and tgkill I can verify that the signal is handled by the sys_kill in the first example and by sys_tgkill in the last example.

现在,如果我为kill、tkill和tgkill启用linux ftrace syscall跟踪程序,我就可以验证信号是由第一个示例中的sys_kill和最后一个示例中的sys_tgkill处理的。

However, none of these system calls is invoked when pressing CTRL-C.

然而,当按CTRL-C时,这些系统调用都不会被调用。

Questions: Which (if any) system call is invoked when CTRL-C is pressed ? Who is passing the instruction pointer to the syscall handler on CTRL-C ? Why is the sender pid in the siginfo_t struct zero on CTRL-C (bug or documented feature) ?

问题:按下CTRL-C时调用哪个(如果有)系统调用?谁将指令指针传递给CTRL-C上的syscall处理程序?为什么siginfo_t struct中的sender pid在CTRL-C上为零(bug或文档化特性)?

1 个解决方案

#1


2  

No system calls get invoked, by any process, when SIGINT gets sent as a result of CTRL-C getting pressed. That's why the sender's PID is zero.

任何进程在按下CTRL-C之后发送SIGINT时都不会调用系统调用。这就是为什么发送者的PID是零。

The signal gets sent from the kernel. Specifically, the TTY module. Each process is (optionally) tied to a terminal, the "controlling terminal". Each terminal has a defined key sequence that generates a SIGINT to all processes that are tied to the terminal. The default key sequence is, of course, CTRL-C.

信号从内核发出。具体来说,遥控模块。每个进程(可选地)绑定到终端,即“控制终端”。每个终端都有一个已定义的键序列,该键序列生成与终端绑定的所有进程的信号。默认的键序列当然是CTRL-C。

You can think of PID 0 as the "kernel process", in this instance.

在本例中,您可以将PID 0视为“内核进程”。

Reference:

参考:

  • The stty(1) manual page.
  • stty(1)手册页。

See if you can spot CTRL-C in stty's output:

看看能否在stty的输出中发现CTRL-C:

$ stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -extproc
  • See also the "NOTES" section of the setpgid(2) manual page for more information on controlling terminals.
  • 有关控制终端的更多信息,请参见setpgid(2)手册页的“NOTES”一节。

#1


2  

No system calls get invoked, by any process, when SIGINT gets sent as a result of CTRL-C getting pressed. That's why the sender's PID is zero.

任何进程在按下CTRL-C之后发送SIGINT时都不会调用系统调用。这就是为什么发送者的PID是零。

The signal gets sent from the kernel. Specifically, the TTY module. Each process is (optionally) tied to a terminal, the "controlling terminal". Each terminal has a defined key sequence that generates a SIGINT to all processes that are tied to the terminal. The default key sequence is, of course, CTRL-C.

信号从内核发出。具体来说,遥控模块。每个进程(可选地)绑定到终端,即“控制终端”。每个终端都有一个已定义的键序列,该键序列生成与终端绑定的所有进程的信号。默认的键序列当然是CTRL-C。

You can think of PID 0 as the "kernel process", in this instance.

在本例中,您可以将PID 0视为“内核进程”。

Reference:

参考:

  • The stty(1) manual page.
  • stty(1)手册页。

See if you can spot CTRL-C in stty's output:

看看能否在stty的输出中发现CTRL-C:

$ stty -a
speed 38400 baud; rows 24; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?;
swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W;
lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -extproc
  • See also the "NOTES" section of the setpgid(2) manual page for more information on controlling terminals.
  • 有关控制终端的更多信息,请参见setpgid(2)手册页的“NOTES”一节。