I have been experimenting with signals and I am facing a problem I can not explain.
I have recreated my issue in this simple C program, in a nutshell I am reading user input in a loop using getline(). The user can fork the process, kill the child process, or exit the main process all together.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
int counter = 0;
void handler(int signum){
counter++;
}
int main(){
int bool = 1;
char *input;
size_t size=100;
input = malloc(sizeof(char)*100);
memset(input,'\0',size);
pid_t id;
struct sigaction sa;
do{
printf("counter=%d\n",counter);
getline(&input,&size,stdin);
if( strncmp(input,"fork",4) == 0 ){
id = fork();
if( id == 0 ){//child
while(1) sleep(1);
free(input);
return 0;
}else if( id > 0 ){//parent
sa.sa_handler = handler;
sigaction(SIGCHLD, &sa, NULL);
}else{//fork failed
free(input); return -1;
}
}else if( strncmp(input,"kill",4) == 0 ){
kill(id,9);
}else if( strncmp(input,"exit",4) == 0 ){
bool = 0;
}
}while(bool == 1);
free(input);
return 0;
}
The strange thing is that if I fork a child process and then kill it, in other words typing to the stdin:
fork
kill
I get stuck in an infinite loop where the following is printed to the stdout indefinitely (which is also an idication that the SIGCHLD was cached when the child was killed)
counter 1
If I remove the signal handler everything seems to be working fine. I know that getline() uses the read() syscall and the SIGCHLD signal causes it's interruption, but apart from that I am almost certain that in the next iteration the getline() function should work just fine. Does anyone have an explanation why getline() stops working?
(I am using the gcc compiler and executing the program on Ubuntu 20.04 LTS)