Search code examples
clinuxsignalsposix

Process dies after SIGINT signal


I don't understand what is happening here, I have a parent process which handles the SIGINT signal and then makes a child. What I expect when I press Ctrl+C is that both processes will print "SIGINT received" and then continue but it turns out that the parent process dies after receiving SIGINT but the child is still there. I can't understand that.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <string.h>

void handler (int sig) {
  printf("SIGINT received\n");
}

void child() {
  while (1) {
    printf("I'm the child\n");
    sleep(1);
  }

  exit(0);
}

int main(int argc, char *argv[]) {
  struct sigaction act;

  memset(&act, 0, sizeof(act));

  act.sa_handler = &handler;
  // Link SIGINT with the handler
  sigaction(SIGINT, &act, NULL);

  // Create child
  if (fork() == 0) child();

  wait(NULL);

  return 0;
}

An example of execution:

$ ./test_signals
I'm the child
^CSIGINT received
I'm the child
SIGINT received
$ I'm the child
I'm the child

So both processes handle SIGINT but the parent dies while the child continues...


Solution

  • The parent process is blocked in the main function and upon receiving the signal, handles it and returns from the call to wait with an error.

    The child is just looping in the while handling SIGINT. When handled code returns where it was (probably blocked in sleep) and it continues to loop.

    That code may illustrates what happens:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <sys/signal.h>
    #include <string.h>
    #include <sys/errno.h>
    
    void handler (int sig) {
      printf("SIGINT received %d\n",getpid());
    }
    
    void child() {
      while (1) {
        printf("I'm the child\n");
        sleep(1);
      }
    
      exit(0);
    }
    
    int main(int argc, char *argv[]) {
      struct sigaction act;
    
      memset(&act, 0, sizeof(act));
    
      act.sa_handler = &handler;
      // Link SIGINT with the handler
      sigaction(SIGINT, &act, NULL);
    
      // Create child
      if (fork() == 0) child();
    
      int r = wait(NULL);
      if (r==-1 && errno==EINTR) printf("signal probably received in parent\n");
    
      return 0;
    }
    

    Be aware that calling printf in a signal handler is forbidden.