SIGCHLD causing segmentation fault, not going into

2019-08-30 23:22发布

问题:

I'm trying to make a simple shell and am adding in functionality to run processes in the background with &. In my main method I basically have:

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);
  }
}

And for my handler I have:

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");
  }
}

I can can have it run a process in the foreground just fine. Running "ls" has the contents print to the screen, then "a" and "b" are printed since it goes into the SIGCHLD handler, but it doesn't go to "c" since it's already been waited on.

However, running something in the background ("ls&") will print "1" and "2", have the parent go back to the prompt, then the child will print the contents to the screen, then segmentation fault. It does not print any of the letters I have in the handler.

I cannot figure out why SIGCHLD is good for children that are already waited on but causes a segmentation fault and never even goes into the handler for processes that were not waited on.

回答1:

You are not following the rules for a signal handler. You can't use printf() or perror(). Read the rules on what is safe to do in a signal handler.

Also the behavior of signal() changes depending on if it's a BSD or SysV style Unix. Linux changes its behavior in glibc based on the presence of _BSD_SOURCE or _GNU_SOURCE and that changes depending on if you call gcc -ansi or gcc -std=c99 or gcc -std=gnu99

You should really be using sigaction() instead of signal().



标签: c shell signals