0

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.

fiveandten
  • 61
  • 1
  • 10
  • You should really make your code a fully compilable version. Its obvious this won't work because it is missing so many things, like variable and function definitions. – Zan Lynx Nov 11 '14 at 17:37

1 Answers1

0

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().

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
  • I see the list of safe functions now. I didn't realize those were unsafe since I've had examples in class that used them in handlers. I've tried sigaction as well with the same results, but I guess I'll give it another shot. – fiveandten Nov 11 '14 at 17:42
  • I still don't understand though what makes printf and perror work in the signal handler for children that have been waited, but not work in the same signal handler for children that were not waited on yet. – fiveandten Nov 11 '14 at 17:43
  • @fiveandten: You can often get away with using printf or other functions but that doesn't make them safe. Consider what happens in the library code if it is *already* in the printf() function when the SIGCHLD arrives... – Zan Lynx Nov 11 '14 at 17:43