【问题标题】:SIGCHLD causing segmentation fault, not going into handlerSIGCHLD 导致分段错误,不进入处理程序
【发布时间】:2014-11-11 17:22:44
【问题描述】:

我正在尝试制作一个简单的 shell,并正在添加功能以使用 & 在后台运行进程。 在我的主要方法中,我基本上有:

int main() {
  if (signal(SIGCHLD, handle) == SIG_ERR)
    perror("Cannot catch SIGCHLD");
  pid_t child = fork();
  if (child == 0)
    execvp(command, arguments);
  else {
    if (background == 1) {
       printf("1");
       backgroundList(command, child);
       printf("2"); }
    else 
      waitpid(child, NULL, 0);
  }
}

对于我的处理程序,我有:

void handle(int s) {
  printf("a");
  if (signal(SIGCHLD, handle) == SIG_ERR)
    perror("Cannot catch SIGCHLD");
  pid_t pid;
  printf("b");
  while((pid = waitpid(0, NULL, WNOHANG)) > 0) {
    printf("c");
    rmBackgroundList(pid);
    printf("d");
  }
}

我可以让它在前台运行一个进程就好了。运行“ls”会将内容打印到屏幕上,然后打印“a”和“b”,因为它进入 SIGCHLD 处理程序,但它不会进入“c”,因为它已经被等待。

但是,在后台运行某些东西(“ls&”)会打印“1”和“2”,让父级返回提示符,然后子级将内容打印到屏幕上,然后分段错误。它不会打印我在处理程序中的任何字母。

我不明白为什么 SIGCHLD 对已经等待的子进程有好处,但会导致分段错误,甚至从未进入未等待进程的处理程序。

【问题讨论】:

  • 你真的应该让你的代码成为一个完全可编译的版本。很明显这是行不通的,因为它缺少很多东西,比如变量和函数定义。

标签: c shell signals


【解决方案1】:

您没有遵守信号处理程序的规则。您不能使用printf()perror()Read the rules on what is safe to do in a signal handler.

signal() 的行为也会根据它是 BSD 还是 SysV 风格的 Unix 而发生变化。 Linux 会根据 _BSD_SOURCE 或 _GNU_SOURCE 的存在来改变其在 glibc 中的行为,并且会根据您调用 gcc -ansigcc -std=c99gcc -std=gnu99 来改变其行为

您确实应该使用sigaction() 而不是signal()

【讨论】:

  • 我现在看到了安全函数列表。我没有意识到这些是不安全的,因为我在课堂上有在处理程序中使用它们的示例。我也尝试过 sigaction,结果相同,但我想我会再试一次。
  • 我仍然不明白是什么让 printf 和 perror 在已等待的孩子的信号处理程序中工作,但在尚未等待的孩子的相同信号处理程序中不起作用。
  • @fiveandten:您通常可以使用 printf 或其他功能,但这并不能使它们安全。考虑一下当 SIGCHLD 到达时如果库代码已经在 printf() 函数中会发生什么...
猜你喜欢
  • 2011-09-16
  • 1970-01-01
  • 2021-10-02
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 2017-03-12
  • 1970-01-01
相关资源
最近更新 更多