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”一节。