我读到杀死父进程将使子进程附加到 init (PPID=1)。
为了测试这一点,我创建了三个 shell 并向第二个 shell 发送了终止信号:
# first process "a"
a$sh
# second process "b"
sh-5.0$ PS1=b$
b$sh
# thrid process "c"
sh-5.0$ PS1=c$
# killing process "b"
c$kill -9 $PPID
c$Killed
a$exit
a$
(killed和exit打印到屏幕上,而不是输入)
但第三个 shell 也被杀死,而不是附加到 init 上。为什么以及由谁执行?
答案1
我将重新创建你的实验:
# First shell
$ echo $$
41903
# Start the second shell
$ bash
$ echo $$ $PPID
41934 41903
# Start the third shell
$ bash
$ echo $$ $PPID
41938 41934
现在,在第二个终端中,我将用来strace
监视第三个 shell 执行的系统调用和处理的信号。请注意,shell 被阻塞等待输入:
$ strace -p 41938
strace: Process 41938 attached
pselect6(1, [0], NULL, NULL, NULL, {[], 8}) = 1 (in [0])
在第三个终端中,我将杀死第二个 shell(我正在跟踪的 shell 的父 shell):
$ kill -9 41934
这时我观察到没有什么在strace
输出中——第三个 shell 仍在运行。
现在,如果我尝试在第一个终端中输入某些内容,我会在输出中看到以下内容strace
:
read(0, 0x7ffd6879ebbf, 1) = -1 EIO (Input/output error)
...
write(2, "exit\n", 5) = 5
...
setpgid(0, 41938) = 0
exit_group(0) = ?
第三个 shell 无法从标准输入(文件描述符 0——read
本例中的第一个参数)读取数据并自行终止。终止父进程似乎以某种方式改变了终端设备的状态,导致read()
子进程失败。
让我们重复这个实验,但这次跟踪第一个 shell——我要杀死的进程的父进程。
$ echo $$
48134
$ bash
$ echo $$ $PPID
48163 48134
$ bash
$ echo $$ $PPID
48169 48163
在单独的终端中,跟踪第一个 shell:
$ strace -p 48134
strace: Process 48134 attached
wait4(-1,
在另一个终端中,杀死第二个 shell:
$ kill -9 48163
最初的贝壳对于它的孩子的死亡做了什么反应?
wait4(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGKILL}], WSTOPPED|WCONTINUED, NULL) = 48163
rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [CHLD], 8) = 0
ioctl(255, TIOCSPGRP, [48134]) = 0
ioctl()
请注意带有参数的调用TIOCSPGRP
。当第一个 shell 注意到其子进程终止时,它将终端的前台进程组 ID 更改回其自身(请注意,fd 255 也是终端设备的打开文件描述符)。这就是导致read()
第三个 shell 失败的原因 - 它尝试从设备读取,但不在前台进程组中。