首页 > 解决方案 > solaris:在标准输入上设置的 O_NDELAY:当进程退出时,shell 退出

问题描述

TLDR:在 Solaris中,如果被子进程O_NDELAY设置为 on stdin,则退出。为什么?bash

以下代码导致交互式bash(v4.3.33) 或tcsh(6.19.00) shell 在进程完成运行后退出:

#include <fcntl.h>

int main() {
  fcntl( 0, F_SETFL, O_NDELAY );

//int x = fcntl( 0, F_GETFL );
//fcntl( 0, F_SETFL, ~(x ^ (~O_NDELAY)) );

  return 0;
}

和我们ksh的版本不受此问题的影响。cshzsh

为了调查我在下面运行bash(类似于在 Linux 上),如下所示:cshtrussstrace

$ truss -eaf -o bash.txt -u'*' -{v,r,w}all bash --noprofile --norc
$ truss -eaf -o csh.txt -u'*' -{v,r,w}all csh -f

完成csh运行该过程后,它会执行以下操作:

fcntl( 0, F_GETFL ) = FWRITE|FNDELAY
fcntl( 0, F_SETFL, FWRITE) = 0

...这给了我一个想法。我将程序更改为上面注释掉的代码,以便切换O_NDELAY. 如果我连续运行两次 bash 不会退出。

标签: solarisfcntl

解决方案


这个答案让我开始走上正确的道路。read(在 Solaris 中)的手册页说:

When attempting to read a file associated with a terminal that has no data currently available:

* If O_NDELAY is set, read() returns 0
* If O_NONBLOCK is set, read() returns -1 and sets errno to EAGAIN

...所以当 bash 尝试读取stdin它时,它返回 0 导致它假设 EOF 被击中。

此页面指示O_NDELAY不应再使用,而是推荐O_NONBLOCK. 我发现了关于O_NDELAY/FIONBIO用于各种风格的 UNIX 的类似声明。

顺便说一句,在 LinuxO_NDELAY == FNDELAY == O_NONBLOCK中,我无法在那个环境中重现这个问题也就不足为奇了。

不幸的是,执行此操作的工具不是我拥有源代码的工具,尽管从我的实验中我找到了解决该问题的方法。

如果没有别的,我可以制作一个O_NDELAY像上面那样删除的简单程序,然后将这个工具的执行包装在一个 shell 脚本中,该脚本总是在另一个之后运行“修复程序”程序。


推荐阅读