在其信号处理程序中中止进程的所有子进程

问题描述 投票:0回答:1

我需要在此进程的信号处理程序中将 SIGABRT 发送给我进程的所有子进程。

在这个答案中在这个答案和其他一些中,建议遍历/proc中的所有进程目录。

为此,需要 opendir、readdir、closedir 等。但它们不是 async-signal-safe。在this answer中,解释说这是因为“opendir()调用malloc(),所以你不能从处理程序中运行它”。据我所知,问题是 malloc() 可以被同一个线程调用两次:在处理程序中和在线程的工作代码中。所以你会遇到死锁,因为它发生在这个问题中:malloc inside linux signal handler cause deadlock.

解决类似的问题在Linux上有没有异步信号安全的读取目录列表的方法?,建议:

如果您事先知道需要读取哪个目录,则可以在信号处理程序外部调用 opendir()(opendir() 调用 malloc(),因此您不能从处理程序内部运行它)并将 DIR* 保留在某处的静态变量。

但在我的例子中,我事先没有目录,因为我不知道在调用信号处理程序时哪些子进程与哪些 pids 将存在。

有什么方法可以在信号处理程序中安全地找到并杀死我的进程的所有子进程?谢谢关注

c++ c linux signals
1个回答
1
投票

简单的方法是为所有孩子使用一个进程组,并立即向其中的所有进程发送信号。

示例程序:

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

// Called by the parent on a SIGABRT
void parent_abort_handler(int signo __attribute__((__unused__))) {
  const char msg[] = "SIGABRT received in parent.\n";
  write(STDOUT_FILENO, msg, sizeof msg);
  kill(0, SIGABRT); // Send signal to all processes in its group
  _exit(0);
}

// Called by the children on a SIGABRT
void child_abort_handler(int signo __attribute__((__unused__))) {
  const char msg[] = "SIGABRT received in child.\n";
  write(STDOUT_FILENO, msg, sizeof msg);
  _exit(0);
}

// Children processes set up a signal handler and wait for a signal
void do_child(void) {
  struct sigaction act;
  memset(&act, 0, sizeof act);
  act.sa_handler = child_abort_handler;
  sigaction(SIGABRT, &act, NULL);
  pause();
}

int main(void) {
  // Make sure this process is in a new process group
  if (setpgid(0, 0) < 0) {
    perror("setpgid");
    return EXIT_FAILURE;
  }


  // Create some child processes
  for (int i = 0; i < 5; i++) {
    pid_t child = fork();
    if (child < 0) {
      perror("fork");
    } else if (child > 0) {
      do_child();
    }
  }

  // Set up parent SIGABRT handler
  struct sigaction act;
  memset(&act, 0, sizeof act);
  act.sa_handler = parent_abort_handler;
  if (sigaction(SIGABRT, &act, NULL) < 0) {
    perror("parent sigaction");
    kill(0, SIGTERM);
    return EXIT_FAILURE;
  }

  printf("Please kill -6 %d\n", (int)getpid());
  fflush(stdout);

  pause();
}

和用法:

$ gcc -Wall -Wextra -O -o sigtest sigtest.c
$ ./sigtest &
Please kill -6 12345
$ kill -6 12345
SIGABRT received in parent.
SIGABRT received in child.
SIGABRT received in child.
SIGABRT received in child.
SIGABRT received in child.
SIGABRT received in child.
$
© www.soinside.com 2019 - 2024. All rights reserved.