为什么 POSIX 要求 system(3) 忽略 SIGINT 和 SIGQUIT? [英] Why does POSIX demand that system(3) ignores SIGINT and SIGQUIT?

查看:76
本文介绍了为什么 POSIX 要求 system(3) 忽略 SIGINT 和 SIGQUIT?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

POSIX 规范说明

system() 函数应忽略 SIGINT 和 SIGQUIT 信号,并在等待命令终止时阻塞 SIGCHLD 信号.如果这可能导致应用程序错过一个会杀死它的信号,那么应用程序应该检查 system() 的返回值,并在命令因接收到信号而终止时采取任何适合应用程序的操作.

The system() function shall ignore the SIGINT and SIGQUIT signals, and shall block the SIGCHLD signal, while waiting for the command to terminate. If this might cause the application to miss a signal that would have killed it, then the application should examine the return value from system() and take whatever action is appropriate to the application if the command terminated due to receipt of a signal.

这意味着启动一个长时间运行的子进程的程序将被 SIGINTSIGQUIT 阻塞很长时间.这是在我的 Ubuntu 18.10 笔记本电脑上编译的测试程序:

This means that a program that starts a long-running sub-process will have SIGINT and SIGQUIT blocked for a long time. Here is a test program compiled on my Ubuntu 18.10 laptop:

$ cat > test_system.c <<< EOF
#include <stdlib.h>

int main() {
    system("sleep 86400");  // Sleep for 24 hours
}
EOF
$ gcc test_system.c -o test_system

如果我启动这个在后台运行的测试程序...

If I start this test program running in the background...

$ ./test_system &
[1] 7489

..然后我可以看到 SIGINT(2) 和 SIGQUIT(3) 在位掩码中被标记为忽​​略.

..Then I can see that SIGINT(2) and SIGQUIT(3) are marked as ignored in the bitmask.

$ ps -H -o pid,pgrp,cmd,ignored
  PID  PGRP CMD                                  IGNORED
 6956  6956 -bash                       0000000000380004
 7489  7489   ./test_system             0000000000000006
 7491  7489     sh -c sleep 86400       0000000000000000
 7492  7489       sleep 86400           0000000000000000

试图用 SIGINT 杀死 test_system 没有效果..

Trying to kill test_system with SIGINT has no effect..

$ kill -SIGINT 7489

.. 但是将 SIGINT 发送到进程组确实会杀死它(这是意料之中的,这意味着进程组中的每个进程都收到信号 - 睡眠将退出,系统将返回).

.. But sending SIGINT to the process group does kill it (this is expected, it means that every process in the process group receives the signal - sleep will exit and system will return).

   $ kill -SIGINT -7489
   [1]+  Done                    ./test_system

问题

  1. 忽略 SIGINTSIGQUIT 的目的是什么,因为该进程仍然可以通过进程组被杀死(这就是你执行 ^C 在终端).
  2. 额外问题:为什么 POSIX 要求应该阻止 SIGCHLD?
  3. 更新 如果 SIGINTSIGQUIT 被忽略以确保我们不会留下孩子,那么为什么不处理 SIGTERM - 这是 kill 发送的默认信号!
  1. What is the purpose of having SIGINT and SIGQUIT ignored since the process can still be killed via the process group (that's what happens when you do a ^C in the terminal).
  2. Bonus question: Why does POSIX demand that SIGCHLD should be blocked?
  3. Update If SIGINT and SIGQUIT are ignored to ensure we don't leave children behind, then why is there no handling for SIGTERM - it's the default signal sent by kill!

推荐答案

SIGINTSIGQUIT 是终端生成的信号.默认情况下,当您分别按 Ctrl+CCtrl+\ 时,它们会发送到前台进程组.

SIGINT and SIGQUIT are terminal generated signals. By default, they're sent to the foreground process group when you press Ctrl+C or Ctrl+\ respectively.

我相信在通过 system 运行孩子时忽略它们的想法是终端应该好像它暂时由孩子和 Ctrl+CCtrl+\ 应该暂时只影响孩子及其后代,而不是父母.

I believe the idea for ignoring them while running a child via system is that the terminal should be as if it was temporarily owned by the child and Ctrl+C or Ctrl+\ should temporarily only affect the child and its descendants, not the parent.

SIGCHLD 被阻塞,以便 systemSIGCHLD 由孩子终止不会触发 SIGCHLD 处理程序(如果您有的话),因为这样的 SIGCHLD 处理程序可能会在 system 收割之前收割由 system 启动的子项.

SIGCHLD is blocked so that system's the SIGCHLD caused by the child terminating won't trigger a SIGCHLD handler if you have one, because such a SIGCHLD handler might reap the child started by system before system reaps it.

这篇关于为什么 POSIX 要求 system(3) 忽略 SIGINT 和 SIGQUIT?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆