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.
You are not following the rules for a signal handler. You can't use
printf()
orperror()
. 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 callgcc -ansi
orgcc -std=c99
orgcc -std=gnu99
You should really be using
sigaction()
instead ofsignal()
.