通过CTRL-C接收SIGINT时,发件人pid为零

时间:2016-02-02 13:22:29

标签: linux linux-kernel signals

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

触发的

为了简单起见,请使用以下使用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;
}

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

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

现在,如果您在启动程序后按CTRL-C,则输出为:

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

如果我在程序中引发SIGINT(通过取消注释代码示例中的行/* raise(SIGINT); */),则输出为:

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

现在,如果我为killtkilltgkill启用了linux ftrace系统调用跟踪器,我可以验证信号是否由sys_kill处理第一个示例和最后一个示例中的sys_tgkill

但是,按CTRL-C时,不会调用这些系统调用。

问题: 按下CTRL-C时会调用哪个(如果有)系统调用? 谁将指令指针传递给CTRL-C上的系统调用处理程序? 为什么发件人pid siginfo_t CTRL-C上的{0}}(错误或记录的功能)?

1 个答案:

答案 0 :(得分:2)

SIGINTCTRL-C被按下而被SIGINT发送时,任何进程都不会调用任何系统调用。这就是发送者的PID为零的原因。

信号从内核发送。具体来说,是TTY模块。每个过程(可选地)连接到终端,即“控制终端”。每个终端都有一个定义的密钥序列,它为绑定到终端的所有进程生成CTRL-C。默认的键序列当然是CTRL-C

在这种情况下,您可以将PID 0视为“内核进程”。

参考:

看看你是否可以在stty的输出中发现$ 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

.tt
  • 有关控制终端的更多信息,另请参阅setpgid(2)手册页的“注意”部分。