gpt4 book ai didi

c - SIGTERM 给所有子进程但不是父进程

转载 作者:太空宇宙 更新时间:2023-11-04 07:26:58 27 4
gpt4 key购买 nike

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

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

但是,使用下面的代码,当我从父级调用 kill(0, SIGTERM) 时,子级不会收到 SIGTERM。来自kill manpage ,看起来所有的 child 都应该得到这个 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))");
}
}

收到需要 fork 的信号后,我执行以下操作

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 中, child 睡了 30 秒。然后我从父级调用 kill(0, SIGTERM)。 children 不会终止。

children 没有得到 SIGTERM 的原因是什么?

最佳答案

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

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

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

关于c - SIGTERM 给所有子进程但不是父进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17517963/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com