【问题标题】:SIGTERM to all children processes but not parentSIGTERM 给所有子进程,但不是父进程
【发布时间】:2013-07-05 06:33:39
【问题描述】:

我有一个通过响应信号来运行的 C 程序。一些信号会导致父节点分叉。这允许在父进程继续响应信号时进行其他处理。

当父母收到一个 SIGTERM 时,我希望分叉的孩子也收到一个 SIGTERM。在父级退出之前,子级完成处理 SIGTERM 并不重要。

但是,使用下面的代码,当我从父级调用 kill(0, SIGTERM) 时,子级不会收到 SIGTERM。从kill manpage 看来,所有孩子都应该得到这个SIGTERM。

我为父级设置了信号处理程序。

static volatile sig_atomic_t done = 0;
const int handled_signals[] = {SIGINT, SIGTERM, 0};

static void set_flag(int signum) {
    switch (signum) {
    /* Intentionally exclude SIGQUIT/SIGABRT/etc. as we want to exit
     * without cleaning up to help with debugging */
    case SIGTERM:
    case SIGINT:
        done = 1;
        break;
    default:
        /* Should be unreachable, but just in case */
        if (signal(signum, SIG_DFL) != SIG_ERR) {
            raise(signum);
        }
    }
}

static int setup_handlers() {
    struct sigaction sa;
    sigset_t block_all;
    int i;

    /* Block all other signals while handling a signal. This is okay as
     * our handler is very brief */
    sigfillset(&block_all);
    sa.sa_mask = block_all;

    sa.sa_handler = set_flag;
    for (i = 0; handled_signals[i] != 0; i++) {
        if (sigaction(handled_signals[i], &sa, NULL)) {
            err_log("Unable to set sigaction");
            return 1;
        }
    }

    /* Ignore SIGCHLD as we don't keep track of child success */
    sa.sa_handler = SIG_IGN;
    if (sigaction(SIGCHLD, &sa, NULL)) {
        err_log("Unable to ignore SIGCHLD");
        return 1;
    }

    return 0;
}

int main() {
    int i;
    sigset_t block_mask, orig_mask;

    setup_handlers();

    /* Block all of our handled signals as we will be using
     * sigsuspend in the loop below */
    sigemptyset(&block_mask);
    for (i = 0; handled_signals[i] != 0; i++) {
        sigaddset(&block_mask, handled_signals[i]);
    }

    if (sigprocmask(SIG_BLOCK, &block_mask, &orig_mask)) {
        err_log("Error blocking signals");
    }

    while (!done) {
        if (sigsuspend(&orig_mask) && errno != EINTR) {
            err_log("sigsuspend");
        }
    }

    /* Kill all children */
    if (kill(0, SIGTERM)) {
        err_log("kill(0, SIGTERM))");
    }
}

得到需要分叉的信号后,我执行以下操作

static int unregister_handlers() {
    struct sigaction sa;
    int i;

    sa.sa_handler = SIG_DFL;

    for (i = 0; handled_signals[i] != 0; i++) {
        if (sigaction(handled_signals[i], &sa, NULL)) {
            err_log("sigaction unregister");
            return 1;
        }
    }

    if (sigaction(SIGCHLD, &sa, NULL)) {
        err_log("sigaction SIGCHLD unregister");
        return 1;
    }

    return 0;
}

void do_fork() {

    switch(fork()) {
    /* Error */
    case -1:
        err_log("fork");
        break;

    /* Child */
    case 0:
        if (unregister_handlers()) {
            _exit(1);
        }
        do_fork_stuff();
        _exit(0);
        break;

    /* Parent */
    default:
        break;
    }
}

do_fork_stuff 中,孩子睡了 30 秒。然后我从父母那里打电话给kill(0, SIGTERM)。孩子们不会终止。

孩子们没有得到 SIGTERM 的原因是什么?

【问题讨论】:

    标签: c linux signals process-group


    【解决方案1】:

    啊,/proc/[PID]/status 的帮助解决了这个问题。

    $ cat /proc/31171/status
    Name:   myprog
    SigQ:   2/16382
    SigPnd: 0000000000000000
    ShdPnd: 0000000000000000
    SigBlk: 0000000000004203
    SigIgn: 0000000000000000
    SigCgt: 0000000180000000
    

    阻塞的信号 (SigBlk) 是这里的问题。当处理程序未注册时,孩子们正在阻止 SIGTERM。删除被阻止的信号解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2011-03-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 2013-06-24
      • 2015-12-23
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多