是否可以检测到哪个管道抛出了 SIGPIPE?

Posted

技术标签:

【中文标题】是否可以检测到哪个管道抛出了 SIGPIPE?【英文标题】:Is it possible to detect which pipe threw a SIGPIPE? 【发布时间】:2014-03-28 23:40:21 【问题描述】:

我正在尝试处理如下工作的服务器:

它有一个父进程 它创建一个“帮助”子进程来处理一些特殊任务 它用管道打开子进程;并使用管道向孩子发出命令。 它还衍生出许多其他子进程(服务器的主要目标是执行各种命令)。

我希望能够检测到何时将管道写入子进程失败;并发出特别通知。

通常,我会通过在父进程中创建自定义 $SIGPIPE 处理程序来实现。

但是,我担心的是父进程启动以执行命令的某些进程可能有自己的管道对它们开放;如果写入 THOSE 管道失败,我想简单地忽略 SIGPIPE。

第一季度。有没有办法让我从 SIGPIPE 处理程序中分辨出哪个打开的管道发出了信号? (我知道每个孩子的 PID,所以 PID 就可以了……或者如果有办法通过文件描述符#s 来做到这一点?)。

第二季度。我可以以某种方式使用local $SIGPIPE 解决问题吗?我的假设是我需要:

在写入该管道之前设置 helper-process-specific local $SIGPIPEprint $HELPER_PIPE(这只发生在一个子程序中) 将 $SIGPIPE 重置为 DEFAULTIGNORE 确保这 3 个操作在各自的块范围内。

【问题讨论】:

不确定你用什么来写命令,但如果写失败perldoc -f syswrite,它应该不返回'undef',因为你也知道你在写哪个孩子,似乎更容易检测到写入调用的失败然后担心看起来充满危险的信号。 @mikew - 正如我的要点所示,一个简单的print $PIPE "string"。此外,我还将检测 write 调用的返回 “可能有自己的管道对他们开放”中的“他们”是什么? 【参考方案1】:

write 系统调用在触发SIGPIPE 的相同情况下返回错误EPIPE,假设SIGPIPE 没有成功终止进程。所以你最好的办法是设置$SIGPIPE = 'IGNORE'(避免死于信号),使用$fh->autoflush(避免PerlIO缓冲,确保立即通知你任何I/O错误),并检查返回每次调用时print 的值。如果 print 返回 false 并且设置了 $!EPIPE,那么您尝试写入一个封闭的管道。如果 print 返回 false 并且未设置 $!EPIPE,则您还有其他问题需要处理。

【讨论】:

@ikegami “它绕过了缓冲的 IO”。 -f syswrite.【参考方案2】:

便携式你无法分辨。但是,您可能会发现您的操作系统支持 SIG_INFO 信息,如果您能以某种方式将其升级到 Perl,siginfo 结构包含一个字段,该字段在 SIGPIPE 上提供 FD 编号。

【讨论】:

为了拯救他人,我从 C 中发现这个 si_fd 字段对 SIGPIPE 没有任何用处。它适用于 SIGPOLL。 si_fd 实际上是联合子结构 _sigpoll 中的一个字段。

以上是关于是否可以检测到哪个管道抛出了 SIGPIPE?的主要内容,如果未能解决你的问题,请参考以下文章

SIGPIPE 如何影响命名管道中的作者?

sigwait 处理 SIGPIPE

为啥我的进程总是收到信号 SIGPIPE,然后管道坏了。我在gdb看到的

SIGPIPE 写入 EBS Docker 应用程序中的关闭管道错误

忽略SIGPIPE信号

为啥存在 SIGPIPE?