【问题标题】:Why call setsid after fork?为什么在 fork 之后调用 setid?
【发布时间】:2017-12-25 07:42:08
【问题描述】:

这是一个关于在another question 中回答Praveen Gollakota's 的问题(这是我应该绕过评论权限的方式吗?)。

他对为什么要分叉两次的问题的回答,本质上是为了确保分叉的进程不是会话领导者,因此无法获得 tty。他给出了这个fork过程的例子,并表明第二个孩子不是会话负责人(第二个fork之后的SID不是第二个孩子的PID)。

1. `Parent`    = PID: 28084, PGID: 28084, SID: 28046
2. `Fork#1`    = PID: 28085, PGID: 28084, SID: 28046
3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085
4. `Fork#2`    = PID: 28086, PGID: 28085, SID: 28085

但是,您也可以在此处看到,在第一次分叉之后和“解耦”步骤之前(我假设这是对 setsid() 的调用),孩子不是会话负责人。因此我的问题是为什么打电话给setsid()?为什么不分叉一次就退出?

我的猜测是,这与会话负责人是控制终端(或其他祖父母)有关。所以接下来的问题是,如果组长退出但会话组长仍然活着的进程会发生什么?

【问题讨论】:

    标签: linux unix fork setsid


    【解决方案1】:
    1. `Parent`    = PID: 28084, PGID: 28084, SID: 28046
    

    此时程序有一个控制终端。

    2. `Fork#1`    = PID: 28085, PGID: 28084, SID: 28046
    

    此时程序仍有一个控制终端。如果父进程退出,这个子进程将属于一个废弃的进程组。它可以setpgid() 到同一会话中的另一个进程组。

    3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085
    

    现在程序在另一个会话中,不能setpgid()切换到原来会话中的进程组。

    4. `Fork#2`    = PID: 28086, PGID: 28085, SID: 28085
    

    相对于init

    【讨论】:

    • 感谢您的回复。我认为“程序”是指产生父进程的进程(即PID 28046)。我可以看到,如果父级在第二步之后退出,第一个子级将属于一个废弃的进程组。但是,这也发生在第四步之后;当第一个孩子退出时,第二个孩子属于一个废弃的进程组。
    • @onlyanegg 确实如此,但此时它属于哪个进程组并不重要 - 它无法重新加入终端会话。
    • 好的,我想我明白了。控制终端是会话的属性。我认为GNU C Library Reference Manual 表示会话中的所有进程都可以对终端进行写访问,这显然是我们在守护进程中不希望的。此外,我们希望通过确保它不是会话负责人来避免它获得自己的 TTY 的可能性。那正确吗?为什么我们关心它无法获得 tty?这只是资源问题吗?
    • @onlyanegg 有多种原因,例如允许在程序仍在运行时释放 TTY(程序还应关闭其标准文件描述符),确保程序不接收挂断信号(来自终端)或继续信号(来自同一会话中的其他进程),并减少交互启动或系统启动之间的行为差​​异(init 通常不使用 TTY 运行进程)。 Other steps 很常见。
    • 好的,如果您想在答案中添加一些信息,我很乐意将其标记为已解决。
    猜你喜欢
    • 2019-07-07
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 2018-12-03
    • 1970-01-01
    相关资源
    最近更新 更多