tcgetpgrp() return 值是什么意思?
what is tcgetpgrp() return value meaning?
问题
tcgetpgrp 的手册页说
When fd refers to the controlling terminal of the calling process, the function tcgetpgrp() will return the foreground process group ID of that terminal if there is one, and
some value larger than 1 that is not presently a process group ID otherwise.
some value
是什么意思,好像有歧义
- 我如何检查它是有效的组 ID 还是其他值,这是否意味着我必须获取系统中所有进程组的列表才能确定 return 值指的是一个有效的进程组?
上下文
当我尝试使用它时,我发现它似乎是 return 当前会话 ID
我已经尝试了很多次,它总是 return 当前会话 ID
some value
是指当前会话 ID 吗?还是特例?或者我的代码有错误?
环境和代码
环境:libc 2.1.2,Linux 2.6.32
代码:
int main(int argc, char *argv[])
{
return getgroup(argc, argv);
}
int getgroup(int argc, char *argv[])
{
if (fork()) {
return OK;
}
sleep(5);
printf("process %d fork, ppid %d, pgid %d, psid %d \n", getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
pid_t gid = tcgetpgrp(STDIN_FILENO);
printf("group id %d \n", gid);
return OK;
}
- what is the meaning of some value, it seems to be ambiguous
这就是它所说的意思,我认为:一些(任意)值不是进程组 ID。 (很可能它实际上 returns 是在它终止之前作为前台组的进程组 ID;这在实践中不太可能是可见的,因为 shell 通常会将另一个进程设置为当其先前在前台的子进程终止时立即进行前台进程)。
- how can i check it to be a valid group id or a other value, does it mean that I have to get the list of all the process groups in the system to figure out if the return value refers to a valid process group?
您可以使用kill
和一个负参数来通知一个进程组(发出信号的进程组将是参数的绝对值),并使用一个信号编号0。这将return -1 如果进程组不存在,errno 设置为 ESRCH
,如果进程组存在则什么也不做(和 return 0)。
(也可以使用killpg
,但是手册页没有说明使用信号编号0的可能性,所以我不确定)。
但是,存在竞争条件:进程组可能在 tcgetgrp
被调用时已经存在,但此后终止;相反,它可能不存在,但具有相同 ID 的新进程组可能已经存在。这使得它实际上只对检查当前进程控制的进程组有用(即它可以防止收割) - 特别是,由当前进程的子进程领导的组(或由当前进程本身领导的组)。
如果这看起来有局限性,请考虑:在什么情况下您实际上需要知道哪个进程组在前台,为什么?
只关注问题标题 什么是 tcgetpgrp() return 值的含义? 这是控制您的终端的进程组 ID求号码到.
为了稍微解释一下事情发生的方式,有必要知道系统如何处理 pids 和进程组 ID,以及终端如何需要知道哪个进程组控制着该终端。
当用户登录时,登录shell,交互并成为进程组组长,使用户终端知道进程组是登录shell。
对于作业控制,对于 shell 构建和执行的每个管道,就在分叉第一个进程之后,它成为进程组领导(通过调用 setpgrp())并生成所有该进程组下的管道中的命令。然后,它使该进程组 id 成为终端控制的进程组,并且终端知道哪个进程组是该终端的控制进程组。
这意味着两件事:
终端一次只能处理一个进程组。将它作为控制终端的其他进程组未链接到它(从某种意义上说,它们确实有一个指向 tty 的指针,但由于 tty 不指向该进程组,read(2)
ing for这些过程是不可能的)。他们将能够再次 read(2)
,一旦他们再次成为前台组(通过 tty
指向该进程组,通过 tcsetpgrp
termios 调用)
shell 仅 对交互式作业执行此操作。更改交互式作业意味着将进程组设置为将要进入前台的进程组。它必须更改等待,以等待该组的进程负责人。这不包括在后台生成的所有作业(或使用命令 bg
或 fg
在后台作业中转换),因为 tty 现在指向不同的进程组。 shell只维护一个前台进程组和多个后台进程,只有前台进程组可以输入。
终端需要知道它链接到哪个进程组有两个原因:
发送信号SIGINT
(Ctrl-C
),SIGHUP
(Ctrl-D
)和SIGQUIT
(Ctrl-]
) 和 SIGSTOP
(Ctrl-X
) 必须发送到前台的进程组,所以它被发送到控制进程组。信号 SIGHUP
被发送到更广泛的进程组,即 session 组。
tty
读取函数需要知道读取终端的进程是否在它指向的进程组中,因此它检查执行读取调用的进程是否具有进程组ID与存储在终端 driver 结构中的进程组相同。如果不匹配,则会出现错误 returned(errno 等于 ENOTTY
)
另一方面,成为进程组组长(创建进程组的唯一方法)会创建一个进程组,其 id 等于发出调用的进程的 pid,因此进程组组长具有相同的它的 pid 和进程组 ID 的编号。
曾经说过...不需要在终端中更新控制进程组 ID。当进程 exit(2)
s 时必须搜索终端,并且搜索 tty 设备的完整列表以删除可以保留在那里的任何控制终端 ID 应该是乏味的。
但是当一个进程组的领导者打开一个tty时,那个tty的进程组就变成了那个领导者的进程组.....所以当一个进程时不需要导航系统中的所有终端死了,只是为了使他们的控制进程组 ID 无效。
正如@davmac 的回答告诉您的那样,还有其他方法可以知道数字 returned 是否是有效的进程组 ID,只需发送一个 0
信号(它可以让你知道一个进程---或进程组---是否存在,你会得到它)。
当然,关于@davmac 指出的竞争条件,考虑重用 pid 的可能性,但由于内核以最近最少使用(或接近它)的方式管理 pid,非常高load 是发生这样的 pid 冲突所必需的。
您始终获得当前进程的进程组 ID 的原因是您始终以交互方式启动程序。尝试在后台启动它,您会看到一个与请求进程的进程组不匹配的进程组(最有可能是 shell 的进程组)
问题
tcgetpgrp 的手册页说
When fd refers to the controlling terminal of the calling process, the function tcgetpgrp() will return the foreground process group ID of that terminal if there is one, and some value larger than 1 that is not presently a process group ID otherwise.
some value
是什么意思,好像有歧义- 我如何检查它是有效的组 ID 还是其他值,这是否意味着我必须获取系统中所有进程组的列表才能确定 return 值指的是一个有效的进程组?
上下文
当我尝试使用它时,我发现它似乎是 return 当前会话 ID 我已经尝试了很多次,它总是 return 当前会话 ID
some value
是指当前会话 ID 吗?还是特例?或者我的代码有错误?
环境和代码
环境:libc 2.1.2,Linux 2.6.32
代码:
int main(int argc, char *argv[])
{
return getgroup(argc, argv);
}
int getgroup(int argc, char *argv[])
{
if (fork()) {
return OK;
}
sleep(5);
printf("process %d fork, ppid %d, pgid %d, psid %d \n", getpid(), getppid(), getpgid(getpid()), getsid(getpid()));
pid_t gid = tcgetpgrp(STDIN_FILENO);
printf("group id %d \n", gid);
return OK;
}
- what is the meaning of some value, it seems to be ambiguous
这就是它所说的意思,我认为:一些(任意)值不是进程组 ID。 (很可能它实际上 returns 是在它终止之前作为前台组的进程组 ID;这在实践中不太可能是可见的,因为 shell 通常会将另一个进程设置为当其先前在前台的子进程终止时立即进行前台进程)。
- how can i check it to be a valid group id or a other value, does it mean that I have to get the list of all the process groups in the system to figure out if the return value refers to a valid process group?
您可以使用kill
和一个负参数来通知一个进程组(发出信号的进程组将是参数的绝对值),并使用一个信号编号0。这将return -1 如果进程组不存在,errno 设置为 ESRCH
,如果进程组存在则什么也不做(和 return 0)。
(也可以使用killpg
,但是手册页没有说明使用信号编号0的可能性,所以我不确定)。
但是,存在竞争条件:进程组可能在 tcgetgrp
被调用时已经存在,但此后终止;相反,它可能不存在,但具有相同 ID 的新进程组可能已经存在。这使得它实际上只对检查当前进程控制的进程组有用(即它可以防止收割) - 特别是,由当前进程的子进程领导的组(或由当前进程本身领导的组)。
如果这看起来有局限性,请考虑:在什么情况下您实际上需要知道哪个进程组在前台,为什么?
只关注问题标题 什么是 tcgetpgrp() return 值的含义? 这是控制您的终端的进程组 ID求号码到.
为了稍微解释一下事情发生的方式,有必要知道系统如何处理 pids 和进程组 ID,以及终端如何需要知道哪个进程组控制着该终端。
当用户登录时,登录shell,交互并成为进程组组长,使用户终端知道进程组是登录shell。
对于作业控制,对于 shell 构建和执行的每个管道,就在分叉第一个进程之后,它成为进程组领导(通过调用 setpgrp())并生成所有该进程组下的管道中的命令。然后,它使该进程组 id 成为终端控制的进程组,并且终端知道哪个进程组是该终端的控制进程组。
这意味着两件事:
终端一次只能处理一个进程组。将它作为控制终端的其他进程组未链接到它(从某种意义上说,它们确实有一个指向 tty 的指针,但由于 tty 不指向该进程组,
read(2)
ing for这些过程是不可能的)。他们将能够再次read(2)
,一旦他们再次成为前台组(通过tty
指向该进程组,通过tcsetpgrp
termios 调用)shell 仅 对交互式作业执行此操作。更改交互式作业意味着将进程组设置为将要进入前台的进程组。它必须更改等待,以等待该组的进程负责人。这不包括在后台生成的所有作业(或使用命令
bg
或fg
在后台作业中转换),因为 tty 现在指向不同的进程组。 shell只维护一个前台进程组和多个后台进程,只有前台进程组可以输入。
终端需要知道它链接到哪个进程组有两个原因:
发送信号
SIGINT
(Ctrl-C
),SIGHUP
(Ctrl-D
)和SIGQUIT
(Ctrl-]
) 和SIGSTOP
(Ctrl-X
) 必须发送到前台的进程组,所以它被发送到控制进程组。信号SIGHUP
被发送到更广泛的进程组,即 session 组。tty
读取函数需要知道读取终端的进程是否在它指向的进程组中,因此它检查执行读取调用的进程是否具有进程组ID与存储在终端 driver 结构中的进程组相同。如果不匹配,则会出现错误 returned(errno 等于ENOTTY
)
另一方面,成为进程组组长(创建进程组的唯一方法)会创建一个进程组,其 id 等于发出调用的进程的 pid,因此进程组组长具有相同的它的 pid 和进程组 ID 的编号。
曾经说过...不需要在终端中更新控制进程组 ID。当进程 exit(2)
s 时必须搜索终端,并且搜索 tty 设备的完整列表以删除可以保留在那里的任何控制终端 ID 应该是乏味的。
但是当一个进程组的领导者打开一个tty时,那个tty的进程组就变成了那个领导者的进程组.....所以当一个进程时不需要导航系统中的所有终端死了,只是为了使他们的控制进程组 ID 无效。
正如@davmac 的回答告诉您的那样,还有其他方法可以知道数字 returned 是否是有效的进程组 ID,只需发送一个 0
信号(它可以让你知道一个进程---或进程组---是否存在,你会得到它)。
当然,关于@davmac 指出的竞争条件,考虑重用 pid 的可能性,但由于内核以最近最少使用(或接近它)的方式管理 pid,非常高load 是发生这样的 pid 冲突所必需的。
您始终获得当前进程的进程组 ID 的原因是您始终以交互方式启动程序。尝试在后台启动它,您会看到一个与请求进程的进程组不匹配的进程组(最有可能是 shell 的进程组)