问题 POSIX进程组


我目前正在将进程组实现到我的操作系统项目的POSIX子系统中。但是,我对此感到有些困惑 POSIX规范(setsid) (以及Wikipedia关于流程组的页面)。

我们的终端层将SIGINT发送到前台进程(组,其id应该等于组长的PID)。在这种情况下,该前台进程(我们的“登录”应用程序)通过调用成为组长 setsid。当用户登录时,程序会分叉并执行用户的shell。在这个阶段,我的理解是我打电话 setpgid 来自分叉的孩子在打电话之前 exec*。这意味着执行的程序从一开始就是过程组的一部分。

如果我想在进程组之外运行新分叉的孩子,我只会打电话 setsid 在打电话之前分叉的孩子 exec*

它是否正确?我应该检查或做的是否有任何非常模糊的事情?

作为一个后续问题,我相信我已经知道,这是一个要求 fork 转移团体会员?或者是必须使用的东西 setpgid 每一次之后 fork 呼叫?我收集过程组转移 fork 来自POSIX的定义 fork

提前致谢。


7030
2018-06-26 01:16


起源



答案:


有趣的问题 - 尤其是因为它长期没有得到部分答案。

POSIX基本定义

来自POSIX定义部分的一些引用:

3.290过程组

允许发送相关进程信号的进程集合。系统中的每个进程都是由进程组ID标识的进程组的成员。新创建的进程加入其创建者的进程组。

3.291进程组ID

表示进程组生命周期内的唯一正整数标识符。

注意:       另请参阅进程ID重用中定义的进程组ID重用。

3.292流程组负责人

进程ID与进程组ID相同的进程。

3.293流程组生命周期

创建进程组时开始的时间段,并且当组中的最后一个剩余进程离开组时结束,这是由于最后一个进程的生命周期结束或者调用setsid()的最后一个剩余进程或setpgid()函数。

注意:       setsid()和setpgid()函数在POSIX.1-2008的系统接口卷中详细定义。

[...]

3.337会议

为工作控制目的而建立的一组进程组。每个进程组都是会话的成员。进程被视为其进程组所属的会话的成员。新创建的进程加入其创建者的会话。进程可以改变其会话成员资格;请参阅setsid()。同一会话中可以有多个进程组。

注意:       setsid()函数在POSIX.1-2008的系统接口卷中详细定义。

3.338会议负责人

创建会话的进程。

注意:       有关详细信息,请参阅POSIX.1-2008的系统接口卷中定义的setsid()函数。

3.339会话生命周期

创建会话与保留为会话成员的所有进程组的生命周期结束之间的时间段。


POSIX系统接口

名称

setsid - 创建会话并设置进程组ID

概要

   #include <unistd.h>

   pid_t setsid(void);

描述

如果调用进程不是进程组领导者,则setsid()函数将创建一个新会话。返回时,调用进程应该是该新进程的会话负责人,应该是新进程组的进程组负责人,并且没有控制终端。调用进程的进程组ID应设置为等于调用进程的进程ID。调用进程应该是新进程组中的唯一进程,也是新进程中唯一的进程。

和:

名称

setpgid - 设置作业控制的进程组ID

概要

   #include <unistd.h>

   int setpgid(pid_t pid, pid_t pgid);

描述

setpgid()函数应加入现有进程组或在调用进程的会话中创建新进程组。

会话负责人的进程组ID不得更改。

成功完成后,具有与pid匹配的进程ID的进程的进程组ID应设置为pgid。

作为一种特殊情况,如果pid为0,则应使用调用进程的进程ID。此外,如果pgid为0,则应使用指示进程的进程ID。


解释

正如定义所表明的那样,会话可能包含多个进程组。在广泛的限制范围内,流程可能会更改流程组(尽管它在任何时候都只属于一个流程组)。会话处理的选项更加有限;基本上,一个进程要么仍然是其原始会话的成员,要么它可以使自己成为新会话的领导者。

复制问题的部分内容:

我们的终端层将SIGINT发送到前台进程(组,其id应该等于组长的PID)。在这种情况下,该前台进程(我们的“登录”应用程序)通过调用setsid成为组长。当用户登录时,程序会分叉并执行用户的shell。在这个阶段,我的理解是我在调用exec *之前从forked子调用setpgid。这意味着执行的程序从一开始就是过程组的一部分。

我怀疑括号应该是'前台进程组(其id应该等于组长的PID)'。根据定义(3.292),进程组负责人是其PID与进程组ID相同的进程。我没有引用相关材料,但我相信将信号发送给流程组负责人是正确的

请注意,前台进程通过调用成为会话负责人 setsid()并且也成为流程组的领导者。我希望登录程序在分叉之后但在执行shell之前将用户的shell设置为进程组负责人(可能还有会话负责人)。所有子进程都自动从其父进程继承进程组和会话;如果你想要它不同,你必须覆盖它。

如果我想在进程组外部运行新分叉的子进程,我只需在调用exec *之前调用分叉子进程中的setsid。

你可以这样做,但它也会创建一个新的会话。你可能想用 setpgid() (现代标准;可能 setpgrp() 这是SVID的旧标准而不是 setsid()

它是否正确?我应该检查或做的是否有任何非常模糊的事情?

是的,这大多是正确的。是的,可能还有一些不起眼的东西要跟踪。例如,您可能需要考虑控制TTY。

作为一个后续问题,我相信我已经知道,是否需要fork来转移组成员身份?或者是否必须在每次fork调用后使用setpgid完成某些操作?我收集进程组是通过fork从POSIX定义fork转移的。

一个孩子过程之后 fork() 属于同一组组(如 /etc/group),也是同一个会话和同一个进程组 - 但它不是会话领导者,也不是进程组领导者。


14
2018-06-26 17:13



很好的研究,这与我在编写shell时所收集的内容一致,但凭借这种经验,我几乎不敢在会话和流程组中发表权威 - 我认为这个问题没有得到解答,因为大多数人都没有也不明白! - ephemient
非常感谢您的深入解答 - 这正是我所需要的。 - Matthew Iselin


答案:


有趣的问题 - 尤其是因为它长期没有得到部分答案。

POSIX基本定义

来自POSIX定义部分的一些引用:

3.290过程组

允许发送相关进程信号的进程集合。系统中的每个进程都是由进程组ID标识的进程组的成员。新创建的进程加入其创建者的进程组。

3.291进程组ID

表示进程组生命周期内的唯一正整数标识符。

注意:       另请参阅进程ID重用中定义的进程组ID重用。

3.292流程组负责人

进程ID与进程组ID相同的进程。

3.293流程组生命周期

创建进程组时开始的时间段,并且当组中的最后一个剩余进程离开组时结束,这是由于最后一个进程的生命周期结束或者调用setsid()的最后一个剩余进程或setpgid()函数。

注意:       setsid()和setpgid()函数在POSIX.1-2008的系统接口卷中详细定义。

[...]

3.337会议

为工作控制目的而建立的一组进程组。每个进程组都是会话的成员。进程被视为其进程组所属的会话的成员。新创建的进程加入其创建者的会话。进程可以改变其会话成员资格;请参阅setsid()。同一会话中可以有多个进程组。

注意:       setsid()函数在POSIX.1-2008的系统接口卷中详细定义。

3.338会议负责人

创建会话的进程。

注意:       有关详细信息,请参阅POSIX.1-2008的系统接口卷中定义的setsid()函数。

3.339会话生命周期

创建会话与保留为会话成员的所有进程组的生命周期结束之间的时间段。


POSIX系统接口

名称

setsid - 创建会话并设置进程组ID

概要

   #include <unistd.h>

   pid_t setsid(void);

描述

如果调用进程不是进程组领导者,则setsid()函数将创建一个新会话。返回时,调用进程应该是该新进程的会话负责人,应该是新进程组的进程组负责人,并且没有控制终端。调用进程的进程组ID应设置为等于调用进程的进程ID。调用进程应该是新进程组中的唯一进程,也是新进程中唯一的进程。

和:

名称

setpgid - 设置作业控制的进程组ID

概要

   #include <unistd.h>

   int setpgid(pid_t pid, pid_t pgid);

描述

setpgid()函数应加入现有进程组或在调用进程的会话中创建新进程组。

会话负责人的进程组ID不得更改。

成功完成后,具有与pid匹配的进程ID的进程的进程组ID应设置为pgid。

作为一种特殊情况,如果pid为0,则应使用调用进程的进程ID。此外,如果pgid为0,则应使用指示进程的进程ID。


解释

正如定义所表明的那样,会话可能包含多个进程组。在广泛的限制范围内,流程可能会更改流程组(尽管它在任何时候都只属于一个流程组)。会话处理的选项更加有限;基本上,一个进程要么仍然是其原始会话的成员,要么它可以使自己成为新会话的领导者。

复制问题的部分内容:

我们的终端层将SIGINT发送到前台进程(组,其id应该等于组长的PID)。在这种情况下,该前台进程(我们的“登录”应用程序)通过调用setsid成为组长。当用户登录时,程序会分叉并执行用户的shell。在这个阶段,我的理解是我在调用exec *之前从forked子调用setpgid。这意味着执行的程序从一开始就是过程组的一部分。

我怀疑括号应该是'前台进程组(其id应该等于组长的PID)'。根据定义(3.292),进程组负责人是其PID与进程组ID相同的进程。我没有引用相关材料,但我相信将信号发送给流程组负责人是正确的

请注意,前台进程通过调用成为会话负责人 setsid()并且也成为流程组的领导者。我希望登录程序在分叉之后但在执行shell之前将用户的shell设置为进程组负责人(可能还有会话负责人)。所有子进程都自动从其父进程继承进程组和会话;如果你想要它不同,你必须覆盖它。

如果我想在进程组外部运行新分叉的子进程,我只需在调用exec *之前调用分叉子进程中的setsid。

你可以这样做,但它也会创建一个新的会话。你可能想用 setpgid() (现代标准;可能 setpgrp() 这是SVID的旧标准而不是 setsid()

它是否正确?我应该检查或做的是否有任何非常模糊的事情?

是的,这大多是正确的。是的,可能还有一些不起眼的东西要跟踪。例如,您可能需要考虑控制TTY。

作为一个后续问题,我相信我已经知道,是否需要fork来转移组成员身份?或者是否必须在每次fork调用后使用setpgid完成某些操作?我收集进程组是通过fork从POSIX定义fork转移的。

一个孩子过程之后 fork() 属于同一组组(如 /etc/group),也是同一个会话和同一个进程组 - 但它不是会话领导者,也不是进程组领导者。


14
2018-06-26 17:13



很好的研究,这与我在编写shell时所收集的内容一致,但凭借这种经验,我几乎不敢在会话和流程组中发表权威 - 我认为这个问题没有得到解答,因为大多数人都没有也不明白! - ephemient
非常感谢您的深入解答 - 这正是我所需要的。 - Matthew Iselin