我有一个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的原因是什么?
1 回答
啊,_2651200的一点帮助解决了这个问题 .
被阻止的信号(
SigBlk
)是这里的问题 . 虽然处理程序未注册,但孩子们阻止了SIGTERM . 删除阻塞的信号解决了这个问题 .