后台进程退出时,关于SIGHUP信号的讨论

问题的提出

  我一直纠结于一个问题。在Linux上,我用“command &”启动了一个后台进程。如果这个后台进程既没有nohup,
又没有setsid,也没有disown的话(如下程序),那么这个进程在终端被关闭时,会被某个信号kill。我的问题是:
  1. 该进程会被谁kill;
  2. 谁发的信号;
#!/bin/bash

sleep 300
./test.sh &

资料搜集来解决问题

  • APUE (中文第二版 9.6节)

如果终端接口检测到调制解调器(或网络)已经断开连接,则将挂掉信号发送给控制进程(会话首进程)

我对这句话的理解是:但终端退出时,某某某会发SIGHUP给shell。但没说SIGHUP是不是会被发给jobs,例如上门的test.sh

  • Bash manpage

SIGNALS
       The shell exits by default upon receipt of a SIGHUP.  Before exiting, an interactive shell resends the SIGHUP to all  jobs,  running  or  stopped.
       Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.  To prevent the shell from sending the signal to a particular job, it should be removed from the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or marked to not receive SIGHUP using disown -h.

  • http://www.flatws.cn/article/program/perl/2011-04-06/19454.html
  • http://stackoverflow.com/questions/5527405/where-is-sighup-from-sshd-forks-a-child-to-create-a-new-session-kill-this-chil

当然,还有很多七七八八的资料,不过它们还是有些不靠谱。上面列出的资料算是我筛选出来的。APUE和Bash manpage肯定是权威资料。第三条资料是某网友的分析,也很好。如下是该网友的结论(纯属转载):

  • CJR平坦软件园内核驱动发现终端(或伪终端)关闭,给对应终端的控制进程(bash)发 SIGHUP 
  • bash收到SIGHUP后,会给各个作业(包括前后台)发送SIGHUP,然后自己退出

此外,还有某网友的总结,

  1. 终端关闭时,该信号被发送到session首进程以及作为job提交的进程(即用 & 符号提交的进程)CJR平坦软件园
  2. session首进程退出时,该信号被发送到该session中的前台进程组中的每一个进程

这两句虽然没有错误,但是容易误导读者,让读者觉得SIGHUP是由终端发给session leader和jobs的。事实上是,SIGHUP被发给了session leader (即shell),然后由session leader发给jobs。至此,我的第一个问题解决了。

     那么SIGHUP是由谁产生的呢?很多资料没有提及,我估计应该是由终端驱动程序产生的 (至少在Linux上是这样的)。虽然,我没有看过终端驱动程序的代码,但从stty这个命令这个命令可以看出一些端倪来。因为stty中有映射CTRL+C,CTRL+\等来产生不同信号的子命令,具体请看一下stty的manpage。当然,对于SIGHUP是不是也是这样,保险的办法还是应该找来终端驱动的代码看一下,毕竟检测终端断开和CTRL+C、CTRL+\是不同的。我的第二个问题也算部分解决了。

    


posted @ 2011-08-14 17:37  coldplayerest  阅读(7649)  评论(2编辑  收藏  举报