title: Why doesn't this process handle a SIGUSR1 anymore?
body: <p>I've got to solve a synchronization problem between two processes and I've got to do it with signals.</p>
  
  <p>Two processes should do a given amount of work, and then signal the other one. This will happen indefinitely.</p>
  
  <p>What happens with my code is: </p>
  
  <p>I send a signal to the parent process, who sends a signal to the child process, who sends a signal to the parent process again, whom is halted and doesn't act anymore.</p>
  
  <p>Ideally, parent and child should signal each other indefinitely.</p>
  
  <pre><code>int main () {
      parent_pid = getpid();
  
      pid_t pid = fork();
      if (pid &lt; 0) {
          syserr_quit("fork error");
      } else if (pid == 0) {
          signal(SIGUSR2, child_work);
          while (1) {}
      } else {
          child_pid = pid;
  
          signal(SIGUSR1, parent_work);
          while (1) {}
      }
  }
  
  void child_work (int signo) {
      sleep(1); // fake child work
  
      if (kill(parent_pid, SIGUSR1) &lt; 0) syserr_quit("kill error");
  
      // wait for parent signal
      pause();
  }
  
  void parent_work (int signo) {
      sleep(1); // fake parent work
  
      if (kill(child_pid, SIGUSR2) &lt; 0) syserr_quit("kill error");
  
      // wait for child signal
      pause();
  }
  </code></pre>
  
  <p>Can't figure out what's wrong since it's a really small amount of code and everything seems to be in place to me.</p>
  
  <p>If somebody wants to spin it up on their machine, here's <a href="https://pastebin.com/EJcGnGey" rel="nofollow noreferrer">a full demo</a> that works after a copy/paste.</p>
  
  <hr>
  
  <h1>Update: sigaction(3) instead of signal(2)</h1>
  
  <p>As per some comments, I resort to the use of <code>sigaction</code> to avoid race condition and stopped using <code>sleep</code> in the demo.
  Docs state that to avoid signal reception from being blocked during the execution of a handler, one must set the <code>SA_NODEFER</code> flag.</p>
  
  <p>Code still behaves faulty, only this time is the child that stops receiving signals.</p>
  
  <p>Snippet is the same as above with the exception of <code>signal</code> being swapped – both times – with </p>
  
  <pre><code>struct sigaction action;
  action.sa_handler = parent/child_work;
  action.sa_flags = SA_NODEFER;
  sigaction(signo, &amp;action, NULL);
  </code></pre>
  
  <hr>
  
  <p><em>Full code</em></p>
  
  <p>To start the signaling, check the  from the console and send a signal (i.e. <code>kill -SIGUSR1 &lt;parentid&gt;</code>)</p>
  
  <pre><code>#include &lt;fcntl.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;signal.h&gt;
  
  void parent_work(int signo);
  void child_work(int signo);
  
  void syserr_quit(char *msg);
  
  pid_t parent_pid;
  pid_t child_pid;
  
  int main () {
      parent_pid = getpid();
      printf("parent pid: %d\n", parent_pid);
  
      pid_t pid = fork();
      if (pid &lt; 0) {
          syserr_quit("fork error");
      } else if (pid == 0) {
          struct sigaction action;
          action.sa_handler = child_work;
          action.sa_flags = SA_NODEFER;
          sigaction(SIGUSR2, &amp;action, NULL);
          while (1) {}
      } else {
          child_pid = pid;
          printf("child pid: %d\n", pid);
  
          struct sigaction action;
          action.sa_handler = parent_work;
          action.sa_flags = SA_NODEFER;
          sigaction(SIGUSR1, &amp;action, NULL);
          while (1) {}
      }
  }
  
  void child_work (int signo) {
      for (int i = 0; i &lt; 100000000; ++i); // fake child work
  
      // signal parent that a write is now possible
      printf("send signal to %d\n", parent_pid); fflush(stdout);
      if (kill(parent_pid, SIGUSR1) &lt; 0) syserr_quit("kill error");
      printf("signal sent\n"); fflush(stdout);
  
      // wait for parent signal
      pause();
  }
  
  void parent_work (int signo) {
      for (int i = 0; i &lt; 100000000; ++i); // fake child work
  
      // signal child that a read is possible
      printf("send signal to %d\n", child_pid); fflush(stdout);
      if (kill(child_pid, SIGUSR2) &lt; 0) syserr_quit("kill error");
      printf("signal sent\n"); fflush(stdout);
  
      // wait for child signal
      pause();
  }
  
  void syserr_quit(char *msg) {
      perror(msg);
      exit(EXIT_FAILURE);
  }
  </code></pre>
  
  <hr>
  
  <h1>Fin</h1>
  
  <p>Alright, guys it seems the updated code didn't work just because I didn't correctly initialize the <code>sigaction</code> mask. It must be done with <code>sigemptyset</code> and you can find out why <a href="https://stackoverflow.com/questions/20684290/signal-handling-and-sigemptyset">right here</a>.</p>
  
  <p>More details in <a href="https://stackoverflow.com/a/43983567/2081434">the answer</a>.</p>