rid*_*ish 25 unix shell signals process-group
简短的问题是,如果shell在没有tty的孤立进程组中应该怎么办?但我建议阅读这个长问题,因为它很有趣.
这是一个有趣而令人兴奋的方式,使用您最喜欢的外壳将您的笔记本电脑变成便携式空间加热器(除非您是其中一个tcsh怪人):
#include <unistd.h>
int main(void) {
if (fork() == 0) {
execl("/bin/bash", "/bin/bash", NULL);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这会导致bash将CPU固定在100%.zsh和鱼做同样的事情,而ksh和tcsh笨拙地谈论工作控制然后龙骨,这有点好,但并不多.哦,这是一个与平台无关的罪犯:OS X和Linux都受到了影响.
我的(可能是错误的)解释如下:子shell检测到它不在前台:tcgetpgrp(0) != getpgrp().因此它试图阻止自己:killpg(getpgrp(), SIGTTIN).但它的进程组是孤立的,因为它的父进程(C程序)是领导者并且死了,并且发送给孤立进程组的SIGTTIN刚刚被删除(否则什么都不能再启动它).因此,子shell不会停止,但它仍然在后台,所以它会立即再次完成.冲洗并重复.
我的问题是,命令行shell如何检测这种情况,它做什么是正确的?我的想法是shell尝试read从stdin,如果read给它EIO就退出.
谢谢你的想法!
编辑:我尝试在/ dev/tty上执行零长度读取(),并且成功,这很糟糕.为了获得EIO,我实际上必须准备从/ dev/tty读取一些数据.
编辑:我的另一个想法是kill(getpgrp(), 0).如果进程组是孤立的,那么我相信这将永远失败.但是,它也可能失败,因为我没有权限发信号通知会话负责人.
编辑:对于后来发现这个的人,我最终做的是在https://github.com/fish-shell/fish-shell/issues/422中描述的.还有,未来怎么样?
strace 说的是这样的情况:
--- SIGTTIN(已停止(tty 输入))@ 0 (0) ---
rt_sigaction(SIGTTIN, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0
ioctl(255, TIOCGPGRP, [9954]) = 0
rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0
杀死(0,信号)= 0
--- SIGTTIN(已停止(tty 输入))@ 0 (0) ---
rt_sigaction(SIGTTIN, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0
ioctl(255, TIOCGPGRP, [9954]) = 0
rt_sigaction(SIGTTIN, {SIG_DFL, [], SA_RESTORER, 0x7fd5f6989d80}, {SIG_IGN, [], SA_RESTORER, 0x7fd5f6989d80}, 8) = 0
杀死(0,信号)= 0
[重复...]
这就是为什么,来自 jobs.c,bash 4.2:
while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1)
{
if (shell_pgrp != terminal_pgrp)
{
SigHandler *ottin;
ottin = set_signal_handler(SIGTTIN, SIG_DFL);
kill (0, SIGTTIN);
set_signal_handler (SIGTTIN, ottin);
continue;
}
break;
}
Run Code Online (Sandbox Code Playgroud)
至于该怎么办……这超出了我的能力范围。但是,我认为这是有用的信息,对于评论来说有点太多了。