我正在学习信号以及当一个进程被分叉时它们的处理程序会发生什么。我从这个问题中了解到“信号必须安装在孩子中”,如果在从父母发送信号之前没有发生这种情况,则不会调用处理程序。我想知道这意味着什么,所以用 strace 看看会发生什么。这是我的代码。我不关心代码批评,除非我做错了导致我的问题:
#include <cassert>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
void sighup(int signo) {
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
void sigint(int signo) {
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
void sigquit(int signo) {
printf("CHILD: I have received a SIGQUIT\n");
exit(0);
}
int main(void) {
int pid;
cout << "Current PID is " << getpid() << endl;
signal(SIGHUP, sighup); /* set function calls */
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
cout << "Waiting to fork..." << endl;
int x; cin >> x;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
/* child */
for (;;); /* loop for ever */
}
else {
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
/* parent */
/* pid hold id of child */
sleep(3);
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
int err = errno;
cout << "sent SIGHUP, err is " << err;
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
err = errno;
cout << "sent SIGINT, err is " << err;
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
err = errno;
cout << "sent SIGINT, err is " << err;
sleep(3);
}
return 0;
}
代码暂停,而用户在显示其 PID 后输入一个整数,以便我可以附加到它。假设父PID为11256,子PID为11313,我输入'11'恢复父;这是 strace 的输出:
ubuntu@ubuntu-xenial:~$ sudo strace -f -p 11256
strace: Process 11256 attached
read(0, "11\n", 1024) = 3
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fad6078fa10) = 11313
rt_sigaction(SIGHUP, {SIG_DFL, [HUP], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, {0x400bd7, [HUP], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [INT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, {0x400bfe, [INT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, 8) = 0
rt_sigaction(SIGQUIT, {SIG_DFL, [QUIT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, {0x400c25, [QUIT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, 8) = 0
nanosleep({3, 0}, strace: Process 11313 attached
0x7ffe3a8df8a0) = 0
[pid 11256] write(1, "\nPARENT: sending SIGHUP\n", 24) = 24
[pid 11256] write(1, "\n", 1) = 1
[pid 11256] kill(11313, SIGHUP) = 0
[pid 11256] nanosleep({3, 0}, <unfinished ...>
[pid 11313] --- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=11256, si_uid=1000} ---
[pid 11313] rt_sigaction(SIGHUP, {0x400bd7, [HUP], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, {0x400bd7, [HUP], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, 8) = 0
[pid 11313] write(1, "CHILD: I have received a SIGHUP\n", 32) = 32
[pid 11313] rt_sigreturn({mask=[]}) = 0
[pid 11256] <... nanosleep resumed> 0x7ffe3a8df8a0) = 0
[pid 11256] write(1, "sent SIGHUP, err is 0\nPARENT: se"..., 45) = 45
[pid 11256] write(1, "\n", 1) = 1
[pid 11256] kill(11313, SIGINT) = 0
[pid 11256] nanosleep({3, 0}, <unfinished ...>
[pid 11313] --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=11256, si_uid=1000} ---
[pid 11313] rt_sigaction(SIGINT, {0x400bfe, [INT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, {0x400bfe, [INT], SA_RESTORER|SA_RESTART, 0x7fad5fe5f4c0}, 8) = 0
[pid 11313] write(1, "CHILD: I have received a SIGINT\n", 32) = 32
[pid 11313] rt_sigreturn({mask=[]}) = 0
[pid 11256] <... nanosleep resumed> 0x7ffe3a8df8a0) = 0
[pid 11256] write(1, "sent SIGINT, err is 0\nPARENT: se"..., 46) = 46
[pid 11256] write(1, "\n", 1) = 1
[pid 11256] kill(11313, SIGQUIT) = 0
[pid 11256] nanosleep({3, 0}, <unfinished ...>
[pid 11313] --- SIGQUIT {si_signo=SIGQUIT, si_code=SI_USER, si_pid=11256, si_uid=1000} ---
[pid 11313] write(1, "CHILD: I have received a SIGQUIT"..., 33) = 33
[pid 11313] lseek(0, -1, SEEK_CUR) = -1 ESPIPE (Illegal seek)
[pid 11313] exit_group(0) = ?
[pid 11313] +++ exited with 0 +++
<... nanosleep resumed> {2, 996222312}) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11313, si_uid=1000, si_status=0, si_utime=894, si_stime=1} ---
restart_syscall(<... resuming interrupted nanosleep ...>) = 0
write(1, "sent SIGINT, err is 0", 21) = 21
lseek(0, -1, SEEK_CUR) = -1 ESPIPE (Illegal seek)
我们可以看到rt_sigaction在父进程中安装 SIGHUP、SIGINT 和 SIGQUIT 处理程序的调用,然后在子进程中也可以看到 SIGHUP 和 SIGINT。
问题1)这就是在孩子身上“安装”处理程序的意思吗?我只是假设(可能是错误的)不会进行系统调用,并且孩子只会在分叉之后“准备好”,而无需实际重新执行首先在父级中执行的代码。我错了吗?
问题 2) 我看到rt_sigaction在孩子中被调用 SIGHUP 和 SIGINT,但不是 SIGQUIT。然而,这个处理程序仍在孩子中被调用(我们看到“孩子:我收到了一个 SIGQUIT”被写入)。当显然它没有安装处理程序时,孩子仍然如何处理这个信号?