Reputation: 1
In original program kill(pid, SIGUSR1); is called first and the pause(); in parent process and In child process pause(); is called first and then kill(getppid(), SIGUSR1); its output is given below
In changed program if I replace the kill(getppid(), SIGUSR1); with pause(); in child process output is totally different I have pasted the output below the code.
Can someone explain me the why the output is changed
**********************ORIGINAL PROGRAM***********************************
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void action(int dummy){
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[]){
pid_t pid;
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
pause();
printf("Child is running\n");
kill(getppid(), SIGUSR1);
}
}
//OUTPUT OF THIS PROGRAM
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
Switching
Parent is running
Switching
Child is running
*********************CHANGED PROGRAM************************
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void action(int dummy){
sleep(1);
printf("Switching\n");
}
int main(int argc, char *argv[]){
pid_t pid;
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
kill(getppid(), SIGUSR1);
printf("Child is running\n");
pause();
}
}
//OUTPUT OF THIS PROGRAM
//Child is running
//User defined signal 1
Upvotes: 0
Views: 391
Reputation: 10271
If a process receives SIGUSR1 before it has set up a signal handler for it (and is not ignoring or holding it), the process will be terminated. (For details. see the signal man page).
Your code (both versions) has several race conditions.
In the first version:
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
pause();
printf("Child is running\n");
kill(getppid(), SIGUSR1);
}
The child will wait for SIGUSR1.
At about the same time, the parent will sleep, then send SIGUSR1 to the child.
The child, after the signal has been received, will do a couple printfs, then send SIGUSR1 to the parent.
At about the same time, the parent will set up a signal handler for SIGUSR1.
It's likely (but not necessarily always the case) that the child will set up the signal handler while the parent is doing the sleep(1); the signal sent from the parent to the child will be caught rather than causing the child to be terminated.
It's likely (but not necessarily always the case) that by the time the child has done its two printfs, the parent has set up the signal handler; the signal sent from the child to the parent will be caught rather than causing the parent to be terminated.
But, since there are race conditions, slight changes in timing can cause things to break.
In the second version:
if((pid=fork())>0){//parent
sleep(1);
while(1){
printf("Parent is running\n");
kill(pid, SIGUSR1);
signal(SIGUSR1, action);
pause();
}
}
else //child code
while(1){//child
signal(SIGUSR1, action);
kill(getppid(), SIGUSR1);
printf("Child is running\n");
pause();
}
The child sends SIGUSR1 to the parent just after it forks, and this will almost certainly happen while the parent is in the middle of the sleep(1). Since the parent hasn't yet set up a handler for SIGUSR1, the signal will terminate it. The shell then prints out User defined signal 1, which is the long name of the SIGUSR1 signal.
Things will work better if you set up a signal handler for SIGUSR1 before the fork. That way, both parent and child will be ready to handle the signal.
Upvotes: 1