为什么在GNU中,我们在shell中使用tcsetpgrp作为后台进程?

时间:2016-01-24 04:51:59

标签: linux shell gnu

我一直在研究这个链接来完成我的shell任务:http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs并且它特别有帮助。我的困惑是,为了再次给出stdin文件描述符的shell控件,我需要在子节点终止后从shell调用tcsetpgrp

How do I get tcsetpgrp() to work in C?

我已经搜索了不同的Stack Overflow问题,但没有一个能正确地告诉我为什么GNU会推广这种方法。由于shell当前位于"后台",tcsetpgrp()会将SIGTTOU发送到我的进程组。当前的解决方案是在调用方法之前忽略它,然后可能将其重置为默认值。我该怎么办?

编辑:我想要注意的是,在shell通过tcsetpgrp()将stdin控制权传递给另一个进程组之前,首先将其设置在另一个进程组中。一旦孩子死了,shell就会调用tcsetpgrp()来回收stdin。 GNU建议将此作为一种可能的实现,但是为了简单起见,它使用了稍微不同的实现here

  

如果后台进程组的成员在其会话中调用tcsetpgrp(),并且调用进程未阻止或忽略SIGTTOU,则会向该后台进程组的所有成员发送SIGTTOU信号。

1 个答案:

答案 0 :(得分:2)

我也即将结束执行Shell程序,并且可以在这个问题上a一口气:

TL; DR:即使此时外壳将是后台进程,但一旦退出最新的前台进程组,它仍需要为其自身回收终端前台;否则,终端将挂起,并且不会有任何进程消耗用户的输入。

这是shell从命令行启动作业时会话的外观:

  1. 在子进程调用execve()之前,它们被分配到一个进程组中,因此将它们作为作业进行管理更为简单;
  2. 由于外壳程序和子进程位于不同的进程组中,并且终端一次只能服务一个进程组,因此外壳程序必须将终端前台捐赠给该子进程组,以便子作业可以直接从用户读取输入并接收信号;
  3. 在前景捐赠之后,shell成为后台进程,但是由于在后台运行shell没有任何意义(它的主要功能是对终端进行读/写并启动作业),因此直到它运行后才继续进行回收前景;
  4. 在最近的子前台进程组退出后,外壳程序必须立即收回前台的另一个原因是,在子前台进程组的时间a)之间,将没有正在运行的进程在消耗终端输入/信号。退出,并且b)当外壳收回前景时。终端实际上​​将挂起并变得无响应; 关于外壳为何必须回收前台本身的原因,这是因为子进程将调用execve()并加载全新的进程映像。强制执行和主张一项合同,其中前台中的每个子进程都将前台返回到Shell进程是非常困难的;
  5. 最后,由于tcsetpgrp()向调用方后台进程发送了一个SIGTTOU,因此外壳程序必须为SIGTTOU注册一个忽略程序处理程序,至少在回收终端前台的过程中要如此。

GNU C库手册还有另一节(28.5.4 Foreground and Background),简要解释了为什么外壳程序必须回收终端forg