Race condition in my POSIX signal handler

The following program returns children that repeat "/ bin / sleep 10". The parent sets up a signal handler for SIGINT, which passes SIGINT to the child. However, sometimes SIGINT is not sent to the child. Why is this and what am I missing?

#include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> pid_t foreground_pid = 0; void sigint_handler(int sig) { printf("sigint_handler: Sending SIGINT to process %d\n", foreground_pid); if ((foreground_pid != 0) && kill(foreground_pid, SIGCONT) == -1) { perror("sending SIGINT to forground process failed"); printf("foreground_pid == %d", foreground_pid); exit(EXIT_FAILURE); } foreground_pid = 0; } int main(int argc, const char *argv[]) { while (1) { pid_t child_pid; if ((child_pid = fork()) == -1) { perror("fork failed"); exit(EXIT_FAILURE); } if (child_pid) { /* parent */ foreground_pid = child_pid; printf("waiting for child (%d) to complete ...\n", child_pid); fflush(stdout); /* install SIGINT signal handler */ struct sigaction sa; struct sigaction old_handler; sa.sa_handler = sigint_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_RESETHAND; sigaction(SIGINT, &sa, NULL); int status = 0; /* wait for child to finish */ if (waitpid(child_pid, &status, 0) == -1) { perror("waitpid failed"); exit(EXIT_FAILURE); } printf(" done.\n"); fflush(stdout); } else { /* child */ char * const argv[] = { "/bin/sleep", "10", NULL}; if (execve(argv[0], argv, NULL) == -1) { perror("execve failed"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } } return EXIT_SUCCESS; } % make && ./foo gcc -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L foo.c -o foo waiting for child (4582) to complete ... ^Csigint_handler: Sending SIGINT to process 4582 done. waiting for child (4583) to complete ... ^Csigint_handler: Sending SIGINT to process 4583 sending SIGINT to forground process failed: No such process foreground_pid == 4583 
+4
source share
1 answer

The tty driver performs SIGINT in the entire process group when you type Ctrl + C ; this includes a child process that will exit in response to it because it does not have an installed handler. So you are duplicating what has already been done, and if the child is still there when the parent tries to execute kill() , it is something like crapshoot.

+6
source

All Articles