I have written a small C program which is creating a child process and then running a shell command using popen. I have created a signal handler to wait for the child process to end while the parent process just runs in an infinite loop. When I am calling 'sleep(5)' after the popen system call the sleep call does not work.
Instead if I put the sleep call before the popen then it is working. Also if I remove the signal handler and just wait for the child process in the parent process then there is no problem(i.e. sleep runs properly anywhere).
//Assume all required header files and function prototypes added
int main()
{
int pid,status;
signal(SIGCHLD,reaper);
pid = fork();
if(pid == 0)
runCommand();
while(1);
}
void runCommand()
{
FILE *pipen;
char *buffer;
buffer = (char*) malloc(100);
/*sleep #1*/ sleep(5);
if ((pipen = popen("uname -a", "r")) == NULL) {
perror("\nError during shell command execution: ");
exit(0);
}
/*sleep #2*/ sleep(5);
fgets(buffer, 100, pipen);
/*sleep #3*/ sleep(5);
printf("\n%s\n",buffer);
exit(0);
}
void reaper(int signal)
{
int status;
waitpid(-1,&status,WNOHANG);
}
When I am running the above program sleep #1 works and the process sleeps for the given time. I am getting to know this by observing the time it takes to print the result of the command (by the printf statement). But for sleep #2 and sleep #3 I expect the process to sleep but that does not seem to be happening as the result of the command is printed on the console instantaneously.
The behavior can be observed by keeping only the sleep #2 or sleep #3 call, and removing the other two sleep calls.
Does anyone know why this is happening?
popen()works by forking a child to execute/bin/sh -c "uname -a". When that child exits, the process receives aSIGCHLDsignal. This interrupts thesleep()call and runs yourreaperfunction.I haven't been able to find this mentioned in any Linux or POSIX documentation, but it's in the SunOS documentation:
You should set the
SIGCHLDhandler back to the default in the child process.