谁应该扼杀工作?
通常,前台和后台作业SIGHUP
在不同情况下被内核或shell发送杀死。
内核什么时候发送SIGHUP
?
内核发送SIGHUP
到控制进程:
- 对于真实(硬件)终端:当在终端驱动程序中检测到断开连接时,例如在调制解调器线路上挂断时;
- 对于伪终端(pty):当最后一个引用 pty 主端的描述符关闭时,例如当您关闭终端窗口时。
内核发送SIGHUP
到其他进程组:
- 到前台进程组,当控制进程终止时;
- 到孤立的进程组,当它变成孤立的并且它已经停止了成员。
控制进程是与控制终端建立连接的会话领导者。
通常,控制进程是您的 shell。所以,总结一下:
- 当真实或伪终端断开/关闭时,内核发送
SIGHUP
到外壳;
SIGHUP
当 shell 终止时,内核发送到前台进程组;
- 如果内核包含已停止的进程,则内核将发送
SIGHUP
到孤立的进程组。
请注意,如果内核不包含已停止的进程,它不会发送SIGHUP
到后台进程组。
什么时候bash
寄SIGHUP
?
Bash发送SIGHUP
到所有作业(前台和后台):
- 当它收到时
SIGHUP
,它是一个交互式外壳(并且在编译时启用了作业控制支持);
- 当它退出时,它是一个交互式登录 shell,并
huponexit
设置了选项(并且在编译时启用了作业控制支持)。
在此处查看更多详细信息。
笔记:
bash
不使用 ;发送SIGHUP
到从作业列表中删除的作业disown
;
- 进程开始使用
nohup
忽略 SIGHUP
。
更多细节在这里。
其他贝壳呢?
通常,shell 会传播SIGHUP
. 在正常出口生成SIGHUP
不太常见。
Telnet 或 SSH
在 telnet 或 SSH 下,连接关闭时会发生以下情况(例如,当您telnet
在 PC 上关闭窗口时):
- 客户被杀;
- 服务器检测到客户端连接已关闭;
- 服务器关闭 pty 的主端;
- 内核检测到主 pty 已关闭并发
SIGHUP
送到bash
;
bash
接收SIGHUP
、发送SIGHUP
到所有作业并终止;
- 每个作业接收
SIGHUP
和终止。
问题
bash
我可以使用and telnetd
frombusybox
或dropbear
SSH 服务器重现您的问题:有时,当客户端连接关闭时,后台作业不会收到SIGHUP
(并且不会终止)。
当服务器(或)关闭 pty 的主端时,似乎会发生竞争情况:telnetd
dropbear
- 通常,
bash
接收SIGHUP
并立即终止后台作业(如预期的那样)并终止;
- 但有时,在处理之前在 pty 的从属端
bash
检测。EOF
SIGHUP
bash
检测到时EOF
,默认立即终止,不发送SIGHUP
。后台作业仍在运行!
解决方案
也可以配置bash
为在正常退出时发送SIGHUP
(包括EOF
):
确保它bash
作为登录 shell启动。huponexit
仅适用于登录外壳,AFAIK。
登录 shell 由-l
选项或前导连字符argv[0]
启用。您可以配置telnetd
为运行/bin/bash -l
或更好地在登录 shell 模式下/bin/login
调用。/bin/sh
例如:
telnetd -l /bin/登录
启用huponexit
选项。
例如:
shopt -s huponexit
bash
每次在 session 中键入此内容或将其添加到.bashrc
or /etc/profile
。
为什么会发生比赛?
bash
仅在安全时解除阻塞信号,并在某些代码段不能被信号处理程序安全中断时阻塞它们。
这样的临界区不时调用中断点,如果在临界区执行时接收到信号,它的处理程序将被延迟,直到下一个中断点发生或临界区退出。
quit.h
您可以从源代码中开始挖掘。
因此,在我们的案例中,似乎有时会在它处于关键部分时bash
收到。处理程序执行被延迟,并在退出临界区或调用下一个中断点之前读取并终止。SIGHUP
SIGHUP
bash
EOF
参考