【问题标题】:SIGINT only received on child process if explicitly caught如果显式捕获,则仅在子进程上收到 SIGINT
【发布时间】:2014-05-05 21:34:25
【问题描述】:

我有以下带有 UNIX 系统调用的测试 C 程序:

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void abide(int sig_num) {
    printf("I, sleeper, will abide to this signal %d!\n", sig_num);
    fflush(stdout);
    exit(0);
}

void refuse(int sig_num) {
    signal(SIGINT, refuse);
    printf("I, sleeper, REFUSE this signal %d!\n", sig_num);
    fflush(stdout);
}

int main(int argc, char *argv[]) {
    if (argc > 1 && strcmp(argv[1], "refuse") == 0) {
        signal(SIGINT, refuse);
    } else if (argc > 1 && strcmp(argv[1], "deaf") == 0) {
        printf("I, sleeper, have been made deaf...\n");
    } else {
        signal(SIGINT, abide);
    }
    printf("I, sleeper, am now sleeping for 10s...\n");
    sleep(10);
    printf("I, sleeper, has terminated normally.\n");
    return 0;
}

然后我有另一个程序,它充当一个小外壳。在我的测试点,它分叉并让子程序执行上面的程序(使用适当的参数)。这个 shell 也忽略了 Ctrl+C 命令使用

signal(SIGINT, SIG_IGN);

结果如下:

MyShell> ./sleeper
I, sleeper, am now sleeping for 10s...
^CI, sleeper, will abide to this signal!
MyShell> ./sleeper refuse
I, sleeper, am now sleeping for 10s...
^CI, sleeper, REFUSE this signal!
I, sleeper, has terminated normally.
MyShell> ./sleeper deaf
I, sleeper, have been made deaf...
I, sleeper, am now sleeping for 10s...
^C^C^C^C    <---- not terminating

第一次运行似乎是正确的。第二个有点奇怪,因为我们实际上忽略了信号,但程序还是终止了。可能是因为我们正在调用sleep(),它被中断了。

但让我感到困惑的是第三个结果。在常规 shell 中,程序终止,但在我的自定义 shell 中没有任何反应。它继续运行。睡眠程序的默认信号处理程序(也终止它)不应该像 abide() 那样执行吗?

感谢您的澄清!

【问题讨论】:

  • 第一次运行的输出是预期的?您的abide 函数调用exit(),但您仍然看到main 的最后一个printf 输出?
  • 我的错。我把输出复制错了。我编辑了帖子。
  • 您似乎刚刚将其编辑掉,这让我认为您向我们展示的不是 真实 控制台输出...
  • 我是用肉眼把它复制过来的,所以这就是为什么会出现这个错误。据我所知,其余的都是正确的。

标签: c linux shell unix sigint


【解决方案1】:

解决了。这个问题有点微妙。使用fork() 后,子进程显然继承了它们的父信号处理程序,即使您之后使用exec() 系统调用也是如此。所以sleeper 的子进程正在使用忽略处理程序。解决方案只是添加默认处理程序

signal(SIGINT, SIG_DFL)

在对fork()exec() 的调用之间。

【讨论】:

  • 这对我来说没有意义。子级不会跨 exec 继承信号处理程序。在exec 之后,原始文本段(即包含处理程序的代码)被蒸发了,那么有什么可以继承的呢?处理程序的地址指向什么?相反,操作系统在exec 之后所做的是将带有处理程序的任何信号重置为其默认配置。所以我想我不明白你的问题或解决方案。你有什么遗漏吗?
  • 据我所知没有。如果我在调用 exec 之前将信号处理程序显式重置为默认值,它会按预期工作,如果我不这样做,则不会。根据uname,我正在运行 Linux 3.2.0-61-generic。我特别使用execvp
  • 我建议加倍检查。我怀疑你在某个地方有一个单独的错误。也许重新发布一个包含所有代码、父母和孩子的问题。
  • 我不确定我是在哪里第一次学习它的,但它在man 7 signal:通过 fork(2) 创建的子代继承了其父代信号处置的副本。在 execve(2) 期间,已处理信号的处置被重置为默认值;忽略信号的处置保持不变。
  • 我编译并运行了你的 shell。所有 4 个案例都按预期工作,包括“聋”案例。它应该在信号上死掉。我的猜测是,在你犯了一些错误的瞬间——运行旧版本或其他任何东西——并开始追逐幻影。
猜你喜欢
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多